コレクション初期化子 コレクション初期化子 初めに.NET 版の Visual Basic では 其れ迄の Visual Basic 6.0 とは異なり 下記の例の様に変数宣言の構文に 初期値を代入する式が書ける様に成った 其の際 1 の様に単一の値 ( 此処では 10) を代入する丈でなく 2 の配列変数の宣言の様に ブレース { } の中にカンマ区切りで初期値のリストを記述し 配列の各要素に初期値を代入出来る様に成った 2 の表現を使用すれば 要素の数丈代入文を書く必要もなくコードは簡潔に成り 配列の各要素の値を把握する上での可読性も向上する Dim x As Integer = 10 Dim num() As Integer = { 10, 20, 30, 40, 50 } 然して Visual Basic 10.0(Visual Basic 2010) では 配列丈ではなくコレクションに付いても コレクション初期化子 (Collection Initializer) と呼ばれる新しい構文を使用して コレクションの各要素への初期化を簡潔に表記出来る様に成った 此処では 此の新しい構文の基本的な使用方法の他 抑々此の構文を使用出来るコレクションオブジェクトの要件は何で有るのかと謂う点や カスタマイズを行った応用例を取り上げる コレクションの基本的な初期化 先ず コレクション初期化子の基本的な使用方法を確認して見る 下記の例では 2 個のコレクションに対して 夫々初期値を代入して居る ( 此の構文は Visual Studio 2008 の Visual Basic 9.0 及び其れ以前のバージョンでは記述出来ない ) Private Sub TestProc01() Dim Col As New ArrayList() From {10, 20, 30} Dim Lst As New List(Of Integer) From {10, 20, 30} 1 の ArrayList オブジェクトは 要素を Object 型として管理する汎用的なコレクションで有る 亦 2 の List (Of Integer) はジェネリックを利用したコレクションで有る ジェネリックに付いての詳細は此処では割愛するが (Of Integer) が要素の型を表して居る 詰まり List (Of Integer) は Integer 型の要素のコレクションで有る 夫々のコレクションに関して コレクション初期化子を使用した構文は次の形式に成る New コレクションクラス () From { 値 1, 値 2, 値 3,... } 此の構文で New キーワードの後にクラス名を記述してコレクションのオブジェクトインスタンスを作成する点は従来の表記方法だが 其の後に From キーワードを続け ブレース { } の中にカンマ区切りで各要素の初期値を書く事が出来る 特に 冒頭の配列変数の初期化と異なる点は From キーワードが有る点で有る 此処では 上記の 1 と 2 の孰れも 順に 10 20 30 の値の要素がコレクションに追加される 此の初期化の表記方法は 実質的には下記の例の様に 其のコレクションの Add メソッドを呼び出して要素を追加する方法と同等で有る Add メソッドの引数には コレクション初期化子の From キーワード以降に列挙された初期値のリスト ( 此処では 10 20 30) が順に渡されて居る -1-
Private Sub TestProc02() Dim Col As New ArrayList() Col.Add(10) Col.Add(20) Col.Add(30) Dim Lst As New List(Of Integer) Lst.Add(10) Lst.Add(20) Lst.Add(30) 上記の例の様に直接記述する場合は 明らかにステートメントの行数が増えて手間が懸かり 亦 前述の例の方が端的に初期化したい内容が伝わり 可読性が高く成る コレクションの 1 個の要素に対して複数の初期値を指定 結局の処 コレクション初期化子はコレクションの Add メソッドを介して要素を追加する事に成る 拠って Add メソッドの引数形式に応じて 初期値のリストの記述方法が変わる 此処で 初期値のリストのバリエーションを確認して見る 下記の例では コレクションの一種で有る Dictionary (Of Integer, String) オブジェクトに対して 各要素の初期化を行って居る 亦 其の次の例はと同等の追加操作を Add メソッドの呼び出しで表わした物で有る Private Sub TestProc03() Dim dict As New Dictionary(Of Integer, String) _ From {{100, " 東地区 "}, {200, " 西地区 "}, {300, " 本部 "}} Private Sub TestProc04() Dim dict As New Dictionary(Of Integer, String) dict.add(100, " 東地区 ") dict.add(200, " 西地区 ") dict.add(300, " 本部 ") 上記の例に登場する Dictionary (Of Integer, String) オブジェクトは 1 個の要素がキーと値のペアで構成されて居る ディクショナリーは 特定のキーに対する値を求める時等に使用する 此の Dictionary (Of Integer, String) オブジェクトもジェネリックが使用されて居る (Of Integer, String) の部分は キーが Integer 型で 値が String 型で有る事を表して居る 此処では 1 個の要素が Integer 型と String 型の 2 個のデータのペアから構成されて居り 上例の 2 に有る様に 此のコレクションの Add メソッドも 2 個の引数を持って居る コレクション初期化子が此れに対応する為には 1 の様に括弧が入れ子に成り 要素毎にブレース { } を使用して 引数の並びを構成する 詰まり 2 の呼び出しの様に 引数に 100, " 東地区 " と 2 個の値を渡す為には 1 の冒頭に有る通り 下記の様な 2 個の値の並びを渡す { 100, " 東地区 " } 此の様に Add メソッドの引数の数に合わせて 1 個の要素を表すリストの値の数も変化する事に成る -2-
コレクション初期化子に対応するオブジェクトの要件 此処迄の処はコレクション初期化子の使用方法を確認したが 此処では コレクション初期化子が使用出来るオブジェクトの要件 ( 即ち オブジェクトインスタンスの作成時に From 句を使用して初期化のリストを記述出来るオブジェクトの要件 ) に付いて確認する Visual Basic 2010(Visual Basic 10.0) の言語仕様に依ると コレクション初期化子に対応するオブジェクトは 下記の 2 個の条件を満たす必要が有る 1. コレクション (collection type) で有る事 2.From 句の初期化のリストに対応した Add メソッドを持つ事 先ず 条件 1 に付いて確認する Visual Basic の言語仕様では コレクション (collection type) に付いても定義が有り IEnumerable インターフェイスを実装したオブジェクト等 幾つかの実装パターンが定義されて居る 簡単に謂うと For Each...Next ループの In キーワードの後ろに記述出来る集合を扱うオブジェクトと謂う事が出来る 亦 Visual Studio 2010 以降のコードエディターで コレクションクラスのインスタンスを作成するコードを入力する時 下図の様に入力候補 ( インテリセンス ) の一覧には From キーワードも列挙されるか何うか判断する事が出来る 次に 条件 2 に付いて補足する コレクション初期化子を使用する為には コレクションと謂う条件 1 を満たした丈では不充分で有る From キーワードの後に記述される初期化のリストを引数として受け取れる適切な Add メソッドが必要で有る 下図は コレクションで有る条件 1 を満たして居ても 適切な Add メソッドが無い場合のエラー ( 波線 ) を表して居る -3-
上図の 2 個の赤い矢印の内 1 のエラーは Add メソッドの引数のパターンが合致していないエラーで有る 既に述べた様に Dictionary (Of Integer, String) オブジェクトの Add メソッドでは 2 個の引数が必要だが 此の例では Integer 型の引数 1 個しか渡して居ない ( メソッド 'Add' には 1 個の引数を受け取るオーバーロードが有りません ) 一方 2 では MyCollection クラスが IEnumerable インターフェイスを実装して定義したオブジェクトだが Add メソッドを定義して居ない為に発生するエラーで有る ( 型 'Project1.MyCollection' には アクセス可能な 'Add' メソッドがない為 ) 2 においてコレクション初期化子を有効にするには Integer 型の引数 1 個を持つ Add メソッドが必要な為 MyCollection の定義に Add メソッド (1 の部分 ) を追加する必要が有る Public Class MyCollection Implements IEnumerable Public Function GetEnumerator1() As IEnumerator _ Implements IEnumerable.GetEnumerator Return New MyEnumerator() End Function Public Sub Add(ByVal dt As Integer) ' End Class 此れで カスタムオブジェクトをコレクション初期化子に対応出来る様に成る コレクション初期化の為の使い勝手を良くするカスタマイズ 最後に 応用例を 1 個取り上げましょう コレクションの各要素が 複数のプロパティを持つオブジェクトで有る場合も有る 下記の例では List (Of Product) と謂う型でコレクションを宣言して居る 詰まり "(Of Product)" と記述して有る事から Product クラスのインスタンスがコレクションの各要素になって居る Product クラスの定義は 例 9 の通りで有る From {New Product() With {.ID = 10,.Price = 200D}, New Product() With {.ID = 20,.Price = 300D}, New Product() With {.ID = 30,.Price = 500D}} Public Class Product Public Property ID As Integer Public Property Price As Decimal End Class 3 上例の Product クラスには ID プロパティと Price プロパティの 2 個のプロパティが有る 3 の様にプロパティの定義には Visual Basic 2010 の新機能で有る Auto-Implemented Properties と呼ばれるプロパティの簡易表現を使用した 此の Product クラスのインスタンスをコレクションの要素として 上記の例の 1 のコレクションに初期値を追加して居るのが 2 以降の部分で有る 此処では Product インスタンスを 3 個追加する為に オブジェクト初期化子を使用して 1 個分のインスタンスは次の様に表現した -4-
New Product() With {.ID = 10,.Price = 200D } 此の With に依るオブジェクト初期化子は Visual Basic 2008 から導入された比較的新しい表現で有る 猶 上記の例の様に 此の様な初期化を 3 個書いても良いが 3 個のインスタンスの違いは プロパティの部分 (ID プロパティと Price プロパティ ) 丈なので 工夫すると 下記の例の様に更に簡潔に成る From {{10, 200D}, {20, 300D}, {30, 500D}} 上記の様な記述を可能にするには 前述した様に 2 個のプロパティを引数として受け取る Add メソッドをコレクションに追加し 其の Add メソッドの中で Product インスタンスを作る様にすれば良い 但し List (Of Product) で使用されて居る List (Of 型 ) と謂う形式のジェネリッククラスは クラスライブラリに定義されたクラスなので 此のクラスに Add メソッドを直接追加出来ない 此の様な既存クラスの定義を変更せずに Add メソッドを追加するので有れば 拡張メソッドを利用する 拠って 上記の例の様にコレクション初期化子を使用出来る様にするには List (Of Product) に適用可能な拡張メソッドとして 下記の Add メソッドを定義すれば良い Namespace MyUtility Public Module ListProductExtensions <System.Runtime.CompilerServices.Extension()> Public Sub Add(ByVal list As List(Of Product), ByVal id As Integer, ByVal price As Decimal) list.add(new Product() With {.ID = id,.price = price}) End Module End Namespace 拡張メソッドの第 1 引数は 拡張対象と成るコレクション自体なので 1 の様に List (Of Product) と成る Add メソッドに渡る実際の引数は 2 に有る様に第 2 引数と第 3 引数に成る 此の拡張メソッドの定義をした後 前記の例のソースコードの先頭に 以下の Imports 文を追加する事で 拡張メソッドが利用出来る様に成り 其の結果 以下の 1 のコレクション初期化子が有効に成る Imports Project1.MyUtility ( 省略 ) From {10, 200D}, {20, 300D}, {30, 500D}} -5-