Visual Basic 2010 の新機能

今回は、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 (英語)

https://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 Function

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 Sub

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

End Class

Class 哺乳動物

    Inherits 動物

End Class

Module Module1

    Public Function 足を数える(ByVal coll As IEnumerable(Of 動物)) As Integer

        Dim count = 0

        For Each a In coll

            count += a.足の数

        Next

        Return count

    End Function

    Sub Main()

        Dim 私の哺乳動物 As New List(Of 哺乳動物)() From {}

        足を数える(私の哺乳動物)

    End Sub

End Module

しかし、哺乳動物も動物なので、「足を数える」関数を哺乳動物にも使いたいと思うのではないでしょうか。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

End Class

Class 名前によって比較

    Implements IComparer(Of ペット)

    ' ...

End Class

Class 犬

    Inherits ペット

End Class

Class オカメインコ

    Inherits ペット

End Class

Module Module1

    Sub Main()

        Dim 犬の名簿 As New SortedList(Of 犬, Object)(New 名前によって比較)

        Dim オカメインコの名簿 As New SortedList(Of オカメインコ, Object)(New 名前によって比較)

    End Sub

End Module

VS2008以前はSortedListのコンストラクターそれぞれにIComparer(Of 犬) または IComparer(Of オカメインコ)を渡す必要がありましたが、反変性を利用するとIComparer(Of ペット) を渡すことが出来るようになります。

共変性 / 反変性自体は2005年頃からCLRでサポートされていましたが、VB2010とC#2010で実際にサポートされるまでは利用できませんでした。