今回は、Visual Basic 2010の新機能の中から、以下のものについてご紹介します。
l コレクション初期化子 (Collection Initializers)
l 共変性 (Covariance) / 反変性 (Contravariance)
詳細については、以下の資料をご参照ください。
l CTPウォークスルードキュメント
https://connect.microsoft.com/VisualStudioJapan/content/content.aspx?ContentID=10212
l New Features in Visual Basic 10 Document (英語)
http://code.msdn.microsoft.com/vbfuture/Release/ProjectReleases.aspx?ReleaseId=1699
コレクション初期化子
コレクション初期化子を利用すると、コレクションのコンストラクターを呼び出す際に、以下のように略された構文でAddを何回でも呼び出せます。
Dim list As New ArrayList() From {1, 2, 3}
ご存知のように、メソッドの種類には普通のメソッドと拡張メソッドの2つがあります(拡張メソッドはVB2008で新たに導入されました)。ArrayListのAddメソッドは普通のメソッドですが、以下の例のように、Addが拡張メソッドであっても、コレクション初期化子を利用することができます。
以下の例は、新しく片方向リスト(Single Linked List)を作成して、1から4までの数字を入れるものです。
Imports System.Runtime.CompilerServices
Class SingleLinkedList (Of T)
Implements IEnumerable(Of T)
Public Tail As SingleLinkedList (Of T)
Public Head As T
Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
' ...
End Function
Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
End Class
Module Module1
<Extension()>
Public Sub Add(Of T)(ByRef coll As SingleLinkedList (Of T), ByVal elem As T)
Dim newColl As New SingleLinkedList (Of T) With {.Head = elem, .Tail = coll}
coll = newColl
End Sub
Sub Main()
Dim x As New SingleLinkedList (Of Integer) From {1, 2, 3, 4}
End Module
尚、Module1のAddメソッドの引数collはByRefで渡されるために、コレクション初期化子経由でAddを呼ぶとコレクションのリファレンスが変更されることになります。
次の例のように、Addは複数の引数を受けることも出来ます。そのようにするとSystem.Collections.Generic.Dictionaryのような型に対してもコレクション初期化子が使えます:
Dim x = New Dictionary(Of Integer, String)() From {{10, "101"}, {20, "202"}}
共変性 / 反変性
VB2008では下記のコードがコンパイルできません。なぜならば、「足を数える」関数には IEnumerable(Of 動物) を渡す必要がありますが、Mainで宣言された「私の哺乳動物」はIEnumerable(Of 哺乳動物)なので、型の間に互換性がないからです。
Class 動物
Public Property 足の数 As Integer
Class 哺乳動物
Inherits 動物
Public Function 足を数える(ByVal coll As IEnumerable(Of 動物)) As Integer
Dim count = 0
For Each a In coll
count += a.足の数
Next
Return count
Dim 私の哺乳動物 As New List(Of 哺乳動物)() From {}
足を数える(私の哺乳動物)
しかし、哺乳動物も動物なので、「足を数える」関数を哺乳動物にも使いたいと思うのではないでしょうか。VB2010では、以下のようにIEnumerable(Of T)の宣言が新機能の共変性を使うようになり、VBコンパイラーが共変性・反変性をサポートするようになったので、それが出来るようになり、上記のサンプルコードも正しくコンパイルされるようになりました。
Interface IEnumerable(Of Out T) : Inherits IEnumerable
Function GetEnumerator() As IEnumerator(Of T)
End Interface
.NETの共変性というのは、例えば、coll As IEnumerable(Of 動物) の代わりに IEnumerable(Of 哺乳動物) を渡すように、より具体的なジェネリックの引数の型を渡すことです。
反変性はその逆になります。例えば、IComparer (Of オカメインコ) の代わりにIComparer (Of ペット)を渡します。オカメインコはペットの一種なので、オカメインコをIComparerで比較しているということは、つまりはペットを比較していることになるからです。
下記は反変性のサンプルコードです。
Class ペット
Public Name As String
Class 名前によって比較
Implements IComparer(Of ペット)
Class 犬
Inherits ペット
Class オカメインコ
Dim 犬の名簿 As New SortedList(Of 犬, Object)(New 名前によって比較)
Dim オカメインコの名簿 As New SortedList(Of オカメインコ, Object)(New 名前によって比較)
VS2008以前はSortedListのコンストラクターそれぞれにIComparer(Of 犬) または IComparer(Of オカメインコ)を渡す必要がありましたが、反変性を利用するとIComparer(Of ペット) を渡すことが出来るようになります。
共変性 / 反変性自体は2005年頃からCLRでサポートされていましたが、VB2010とC#2010で実際にサポートされるまでは利用できませんでした。