|
■No87461 (うるち米 さん) に返信 > ※ただし、Interfaceを実装したクラス側に書いた以下のPrivateメソッドが外部から呼び出される仕組みがまだ理解できていません。 > Private Function IDialog_ShowDialog(owner As Global.System.Windows.Forms.IWin32Window) As DialogResult Implements IExampleDialog.ShowDialog
大雑把な解説になりますが:
呼び出す際には、『f.ShowDialog(Me)』というコードだったわけですよね。
このとき、変数 f は IExampleDialog 型としていますから、これは 「IExampleDialog インターフェイスの ShowDialog メソッド」を 通じて呼び出していることになります。 このメソッドは、インターフェイスで公開されたものであるため、 呼び出し元からでも問題なくアクセスすることができます。
一方、変数 f で保持されているインスタンスは、Form1/Form2 型のオブジェクトでしたので、 最終的には、各クラスで「Implements IExampleDialog.ShowDialog」されたメソッド実装が呼ばれます。
この実装先のメソッドのスコープは、実際には Public でも Private でも構いませんし、メソッド名も IExampleDialog_ShowDialog だろうと IDialog_ShowDialog だろうと、どんな名前でも自由です。
あるいは Private Function IDialog_ShowDialog ではなく、 Public Function ShowDialog のままで Implements させることもできます。 ただしその場合、元のメソッド名と被ってしまうので、実装時には Public Overloads Function ShowDialog(owner As IWin32Window) As DialogResult Implements IExampleDialog.ShowDialog もしくは Public Shadows Function ShowDialog(owner As IWin32Window) As DialogResult Implements IExampleDialog.ShowDialog の形式を取る必要があります。
> 今度、案2(抽象クラスというのですね)についても試してみようと思います。
個人的には 案1 がお奨めです。
案1 の実装の場合、呼び出し側で利用できるのは、キャストしない限りは 「IExampleDialog に実装されたメソッド」に限定されます。 ということは、コーディング時に f.何某 で呼び出される IntelliSense に表示されるメンバーも、 必要最低限なものだけが浮き彫りになるので、利用側としてもわかりやすくなると思います。
しかし 案2 だと、呼び出し元では必要としない、素の Form クラスのメンバーまで表示されてしまいます。 それが必要な場合もありますし、共通で実装しなければならない機能が多い場合は、 案2 の方が実装しやすいケースもありますので、使い分けということにはなりますけれどね。
それと、今回の本題である『条件により類似のモーダルフォームを切り替える』という目的のために、 案1/案2 では、「f As IExampleDialog = New Form1()」のようにして、インスタンスの型と それを受けとる変数の型にズレが生じる結果となっています。
これが分かり難いという場合には、ヘルパーととなる Factory を用意しておくと便利です。
Using f = DialogFactorySample.CreateDialog(…) If f.ShowDialog(Me) = DialogResult.Cancel Then Return End If : End Using
上記の場合、DialogFactorySample クラスはたとえば
Public Shared Function CreateDialog(…) As IExampleDialog If 条件1 Then Return New Form1() ElseIf 条件2 Then Return New Form2() Else : End If End Function
のような実装をイメージしています。(Shared にするかどうかはお好みで)
ついでに言えば、Dispose 処理もカプセル化してしまって、 呼び出し側で Using を呼ぶ手間も省いてしまうのも良いかと思います。
つまり VB の InputBox 関数のような実装にして、ダイアログの結果を メソッドの戻り値だけで表現するようにする、ということです。
[案3] '呼び出す側 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim result = Form2.ShowModalDialog(Me) If result Is Nothing Then Label1.Text = "Cancel された" Else Label1.Text = result.Prop1 End If End Sub
'呼ばれる側 Public Class Form2 Public Shared Function ShowModalDialog(owner As IWin32Window) As ExampleDialogResult Using dlg As New Form2() If dlg.ShowDialog(owner) = DialogResult.Cancel Then Return Nothing Else Return New ExampleDialogResult("VB", 2017, True) End If End Using End Function
'コンストラクタを非公開にして、外部から生成できなくしてしまう Private Sub New() InitializeComponent() End Sub End Class
'返却値のためのクラス(こういったものを作るのが面倒なら、タプルで代用しても良い) Public Class ExampleDialogResult Public ReadOnly Property Prop1 As String Public ReadOnly Property Prop2 As Integer Public ReadOnly Property Prop3 As Boolean Public Sub New(s As String, i As Integer, b As Boolean) Prop1 = s Prop2 = i Prop3 = b End Sub End Class
上記の 案3 は、当初の「条件により類似のモーダルフォームを切り替える」という 目的からは離れてしまうので、仮に上記のように Dispose まで内包させるとしても、 多態性(polymorphism)を実装するために、案1/案2 のように 共通部分となるインターフェイスやクラスは用意した方が良いとは思います。
|