読者です 読者をやめる 読者になる 読者になる

VB.NETでもジェネリックなメソッドを実装したい

VB.NET

気分の問題

これまた特に需要なんてものはないんですが、VBで型パラメータで指定したインスタンスを生成したりするメソッドを定義したくなったのでちょっと調べてみました。

リフレクションと組み合わせたら泥沼のコードをいっぱい書けるんじゃないかなーって

余談ですが、弊社はいままでリフレクはリフレクションの略だと思ってました。 音楽ゲームだったんですね。

カニ味噌スパゲッティ

毎度恒例のこころぴょんぴょん仕様です。

Imports こころぴょんぴょん = System.Console

Module Module1

    Sub Main()

        Dim a As Generic1(Of HogeA) = New Generic1(Of HogeA)()
        Dim b As Generic1(Of HogeB) = New Generic1(Of HogeB)()

        Dim c As HogeA = a.Generate()
        Dim d As HogeB = b.Generate()
        c.HelloA()
        d.HelloB()

        こころぴょんぴょん.WriteLine()

        c = Generic2.Generate(Of HogeA)()
        d = Generic2.Generate(Of HogeB)()
        c.HelloA()
        d.HelloB()

        こころぴょんぴょん.ReadLine()
    End Sub

End Module

Class Generic1(Of T As {New, IHoge})
    Public Function Generate() As T
        こころぴょんぴょん.WriteLine("Generate():{0}", GetType(T))
        Dim i = New T()
        i.Hello()
        Return i
    End Function
End Class

Class Generic2
    Public Shared Function Generate(Of T As {New, IHoge})() As T
        こころぴょんぴょん.WriteLine("Generate():{0}", GetType(T))
        Dim i = New T()
        i.Hello()
        Return i
    End Function
End Class

Interface IHoge
    Sub Hello()
End Interface

Class HogeA
    Implements IHoge

    Public Sub HelloA() Implements IHoge.Hello
        Console.WriteLine("HogeA")
    End Sub
End Class

Class HogeB
    Implements IHoge

    Public Sub HelloB() Implements IHoge.Hello
        Console.WriteLine("HogeB")
    End Sub
End Class

メソッドHelloを宣言したインターフェースIHogeを定義し、型パラメータの制約として引数を取らないコンストラクタを持ちなおかつIHogeを実装したクラスのみを受け付けるクラスとメソッドを宣言しています。

それぞれのジェネリッククラス及びジェネリックメソッドは型パラメータのインスタンスを生成しインターフェースが宣言しているメソッドを実行してからインスタンスを呼び出し元へ返却しています。 なおNew制約を付けないとジェネリッククラス内でインスタンスの生成が出来ません。 当たり前ですね。型パラメータに渡されるクラスなんてジェネリッククラスの宣言時には分かりませんし、制約が無ければ引数を取らないコンストラクタを含まないクラスだって渡せます。そうなると実行時にコンストラクタの呼び出しに失敗します。

ちなみにジェネリックで指定した型であることを明示するために変数の型を明記してますが、

Dim c = a.Generate()

Dim c = Generic2.Generate(Of HogeA)()

でもちゃんと型推論してくれるので大丈夫です。

余談ですが、インターフェースを実装したクラスのメソッドを呼び出すとき、参照の型がインターフェースの場合はインターフェースで宣言したメソッド名を使用しますが、参照の型がクラスの場合はクラスで宣言したメソッド名で呼び出します。

さらに余談ですが、C#ではnew()制約は型パラメータ制約の最後にしないといけないという制約がありますが、VBではそういうのはないっぽいです。

型パラメーターの制約 (C# プログラミング ガイド)

型リスト (Visual Basic)

おしまい