ジェネリック

Net Framework 2.0ではジェネリックが搭載されました。ジェネリックについては以前に型総称性で紹介しました。このときにはC++でテンプレートが使えたもののJava Genericは搭載されたばかりで盛んに使われている状況にはありませんでした。今ではNet Frameworkに当然のようにクラスライブラリに使われ、アプリケーションプログラマにとっても身近な存在になったと感じています。

コレクションなどで提供されているジェネリックライブラリを使うことはそれほど難しいことではないと思います。一方メソッドやクラスを作るのにもジェネリックを使うと今までにないものができます。

単純な例でVisual BasicのIIf関数のジェネリック版です。

1
2
3
Public Function IIf(Of T)(ByVal expression As Boolean, ByVal truePart As T, ByVal falsePart As T) As T
If expression Then Return truePart Else Return falsePart
End Function

(Of T)のTは型引数と呼びます。上記IIfを使うとReturn値のデータ型が、引数に合致したものと型推論されるので、以下のように文字列変数に代入するときにもいちいち型キャストする必要がなくなります(Strict
Onでも)。

1
Dim s As String = IIf(True, "True", "False")

型推論を使わずにIIf(Of String)と明示的に型を指定してもOKです。
つぎにキャストを行う関数を作ってみました。

1
2
3
Public Function Cast(Of Destination)(ByVal Source As Object) As Destination
Return CType(Source, Destination)
End Function

こうなるとただのシンタックスシュガーなのですが次のような使い方ができます。

1
Dim s As String = Cast(Of String)(123)

型引数を持ったクラスを作ることもできます。C++のテンプレートはプリプロセッサで実現されているので、型引数が指定(実体化)されないかぎりコンパイルチェックが掛かりません。それに対しNet Frameworkではジェネリッククラスそのものにコンパイルチェックが掛かり、型引数に対して定義されていないメソッドやプロパティの呼び出しはできません。それは安全性が増していて、生成されるコードも小さくなることを意味します。型引数にはどんな型が指定されるかわからないのにどうしてメソッドやプロパティを呼び出せるのかとの疑問がわきます。実際上記のIIfでは関数内でtruePartやfalsePartに対するメソッド・プロパティ呼び出しはすべてのデータ型の基底型であるObjectのメソッドしか使用することができません。

そこで使用するのが型制約です。型制約は型引数に指定できる型を制限する代わりに制約に指定した型のメソッド・プロパティを呼び出せるようにする物です。型制約は(Of T As Control)のようにAsを使って指定します。

以下余談、Visual Basicに有ったらいいなと思うもの、無名メソッド(C#)・typedef(C#)・プロパティによるインタフェース委任(Delphi)・メソッド解決節(Delphi)。

Net Frameworkとは関係のない余談ですが、Delphi for Win32にはクラス参照と呼ばれる、型を変数として扱えるものがあります。これとジェネリックを組み合わせると非常に柔軟なプログラミングができるような気がします。