Visual Basic では匿名型がサポートされています。これを使用すると、データ型のクラス定義を記述せずにオブジェクトを作成できます。 クラスは、コンパイラによって生成されます。 クラスには使用可能な名前がなく、 Objectから直接継承され、オブジェクトの宣言で指定したプロパティが含まれています。 データ型の名前が指定されていないため、 匿名型と呼ばれます。
次の例では、Name
とPrice
の 2 つのプロパティを持つ匿名型のインスタンスとして変数product
を宣言して作成します。
' Variable product is an instance of a simple anonymous type.
Dim product = New With {Key .Name = "paperclips", .Price = 1.29}
クエリ式では、匿名型を使用して、クエリによって選択されたデータの列を結合します。 特定のクエリで選択される列を予測できないため、結果の型を事前に定義することはできません。 匿名型を使用すると、任意の数の列を任意の順序で選択するクエリを記述できます。 コンパイラは、指定したプロパティと指定した順序に一致するデータ型を作成します。
次の例では、 products
は製品オブジェクトの一覧であり、それぞれに多くのプロパティがあります。 変数 namePriceQuery
は、実行時に、 Name
と Price
の 2 つのプロパティを持つ匿名型のインスタンスのコレクションを返すクエリの定義を保持します。
Dim namePriceQuery = From prod In products
Select prod.Name, prod.Price
変数 nameQuantityQuery
は、実行時に、 Name
と OnHand
の 2 つのプロパティを持つ匿名型のインスタンスのコレクションを返すクエリの定義を保持します。
Dim nameQuantityQuery = From prod In products
Select prod.Name, prod.OnHand
匿名型のコンパイラによって作成されるコードの詳細については、「 匿名型の定義」を参照してください。
注意事項
匿名型の名前はコンパイラによって生成され、コンパイルによって異なる場合があります。 プロジェクトの再コンパイル時に名前が変更される可能性があるため、匿名型の名前を使用したり、匿名型に依存したりしないでください。
匿名型の宣言
匿名型のインスタンスの宣言では、初期化子リストを使用して型のプロパティを指定します。 プロパティは、匿名型を宣言する場合にのみ指定でき、メソッドやイベントなどの他のクラス要素は指定できません。 次の例では、 product1
は、 Name
と Price
の 2 つのプロパティを持つ匿名型のインスタンスです。
' Variable product1 is an instance of a simple anonymous type.
Dim product1 = New With {.Name = "paperclips", .Price = 1.29}
' -or-
' product2 is an instance of an anonymous type with key properties.
Dim product2 = New With {Key .Name = "paperclips", Key .Price = 1.29}
プロパティをキー プロパティとして指定する場合は、それらを使用して、2 つの匿名型インスタンスの等価性を比較できます。 ただし、キー プロパティの値は変更できません。 詳細については、このトピックで後述する「キーのプロパティ」セクションを参照してください。
匿名型のインスタンスを宣言することは、オブジェクト初期化子を使用して名前付き型のインスタンスを宣言するのと同じであることに注意してください。
' Variable product3 is an instance of a class named Product.
Dim product3 = New Product With {.Name = "paperclips", .Price = 1.29}
匿名型プロパティを指定する他の方法の詳細については、「 方法: 匿名型宣言でプロパティ名と型を推論する」を参照してください。
主要な特性
キー プロパティは、いくつかの基本的な方法でキー以外のプロパティと異なります。
2 つのインスタンスが等しいかどうかを判断するために、キー プロパティの値のみが比較されます。
キー プロパティの値は読み取り専用であり、変更することはできません。
匿名型のコンパイラによって生成されるハッシュ コード アルゴリズムには、キー プロパティ値のみが含まれます。
平等
匿名型のインスタンスは、同じ匿名型のインスタンスである場合にのみ等しい場合があります。 コンパイラは、次の条件を満たしている場合、2 つのインスタンスを同じ型のインスタンスとして扱います。
これらは同じアセンブリで宣言されます。
プロパティの名前は同じで、推論された型は同じで、同じ順序で宣言されます。 名前の比較では、大文字と小文字は区別されません。
それぞれで同じプロパティがキー プロパティとしてマークされます。
各宣言の少なくとも 1 つのプロパティがキー プロパティです。
キー プロパティを持たない匿名型のインスタンスは、それ自体とのみ等しくなります。
' prod1 and prod2 have no key values.
Dim prod1 = New With {.Name = "paperclips", .Price = 1.29}
Dim prod2 = New With {.Name = "paperclips", .Price = 1.29}
' The following line displays False, because prod1 and prod2 have no
' key properties.
Console.WriteLine(prod1.Equals(prod2))
' The following statement displays True because prod1 is equal to itself.
Console.WriteLine(prod1.Equals(prod1))
キー プロパティの値が等しい場合、同じ匿名型の 2 つのインスタンスが等しくなります。 次の例は、等価性のテスト方法を示しています。
Dim prod3 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod4 = New With {Key .Name = "paperclips", Key .Price = 1.29}
' The following line displays True, because prod3 and prod4 are
' instances of the same anonymous type, and the values of their
' key properties are equal.
Console.WriteLine(prod3.Equals(prod4))
Dim prod5 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod6 = New With {Key .Name = "paperclips", Key .Price = 1.29,
.OnHand = 423}
' The following line displays False, because prod5 and prod6 do not
' have the same properties.
Console.WriteLine(prod5.Equals(prod6))
Dim prod7 = New With {Key .Name = "paperclips", Key .Price = 1.29,
.OnHand = 24}
Dim prod8 = New With {Key .Name = "paperclips", Key .Price = 1.29,
.OnHand = 423}
' The following line displays True, because prod7 and prod8 are
' instances of the same anonymous type, and the values of their
' key properties are equal. The equality check does not compare the
' values of the non-key field.
Console.WriteLine(prod7.Equals(prod8))
Read-Only 値
キー プロパティの値は変更できません。 たとえば、前の例の prod8
では、 Name
フィールドと Price
フィールドは read-only
されますが、 OnHand
は変更できます。
' The following statement will not compile, because Name is a key
' property and its value cannot be changed.
' prod8.Name = "clamps"
' OnHand is not a Key property. Its value can be changed.
prod8.OnHand = 22
クエリ式からの匿名型
クエリ式では、必ずしも匿名型を作成する必要はありません。 可能であれば、既存の型を使用して列データを保持します。 これは、クエリがデータ ソースからレコード全体を返すか、各レコードから 1 つのフィールドのみを返す場合に発生します。 次のコード例では、 customers
は Customer
クラスのオブジェクトのコレクションです。 クラスには多くのプロパティがあり、クエリ結果に 1 つ以上のプロパティを任意の順序で含めることができます。 最初の 2 つの例では、名前付き型の要素がクエリによって選択されるため、匿名型は必要ありません。
custs1
cust.Name
は文字列であるため、文字列のコレクションが含まれています。Dim custs1 = From cust In customers Select cust.Name
custs2
には、customers
の各要素がCustomer
オブジェクトであり、要素全体がクエリによって選択されるため、Customer
オブジェクトのコレクションが含まれています。Dim custs2 = From cust In customers Select cust
ただし、適切な名前付き型は常に使用できるわけではありません。 1 つの目的で顧客名と住所、別の目的の顧客 ID 番号と場所、3 番目の顧客名、住所、注文履歴を選択できます。 匿名型を使用すると、最初に結果を保持する新しい名前付き型を宣言することなく、任意の順序でプロパティの任意の組み合わせを選択できます。 代わりに、コンパイラはプロパティのコンパイルごとに匿名型を作成します。 次のクエリでは、customers
内の各Customer
オブジェクトから顧客の名前と ID 番号のみが選択されます。 したがって、コンパイラは、これら 2 つのプロパティのみを含む匿名型を作成します。
Dim custs3 = From cust In customers
Select cust.Name, cust.ID
匿名型のプロパティの名前とデータ型の両方が、引数から Select
、 cust.Name
、および cust.ID
に取得されます。 クエリによって作成される匿名型のプロパティは、常にキー プロパティです。 次のFor Each
ループでcusts3
が実行されると、結果は、Name
とID
の 2 つのキー プロパティを持つ匿名型のインスタンスのコレクションになります。
For Each selectedCust In custs3
Console.WriteLine(selectedCust.ID & ": " & selectedCust.Name)
Next
custs3
によって表されるコレクション内の要素は厳密に型指定されており、IntelliSense を使用して使用可能なプロパティ間を移動し、その型を確認できます。
詳細については、「Visual Basicでの LINQ の概要」を参照してください。
匿名型を使用するかどうかを決定する
匿名クラスのインスタンスとしてオブジェクトを作成する前に、それが最適なオプションかどうかを検討してください。 たとえば、関連するデータを格納する一時オブジェクトを作成する場合、完全なクラスに含まれる可能性のある他のフィールドやメソッドは必要ない場合は、匿名型を使用することをお勧めします。 匿名型は、宣言ごとに異なるプロパティを選択する場合や、プロパティの順序を変更する場合にも便利です。 ただし、プロジェクトに同じプロパティを持つ複数のオブジェクトが固定順序で含まれている場合は、クラス コンストラクターで名前付き型を使用することで、より簡単に宣言できます。 たとえば、適切なコンストラクターを使用すると、匿名型の複数のインスタンスを宣言するよりも、 Product
クラスの複数のインスタンスを宣言する方が簡単です。
' Declaring instances of a named type.
Dim firstProd1 As New Product("paperclips", 1.29)
Dim secondProd1 As New Product("desklamp", 28.99)
Dim thirdProd1 As New Product("stapler", 5.09)
' Declaring instances of an anonymous type.
Dim firstProd2 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim secondProd2 = New With {Key .Name = "desklamp", Key .Price = 28.99}
Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}
名前付き型のもう 1 つの利点は、コンパイラがプロパティ名を誤って誤ってキャッチできることです。 前の例では、 firstProd2
、 secondProd2
、および thirdProd2
は、同じ匿名型のインスタンスを想定しています。 ただし、次のいずれかの方法で誤って thirdProd2
を宣言した場合、その型は firstProd2
と secondProd2
の型とは異なります。
' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}
' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = "5.09"}
' Dim thirdProd2 = New With {Key .Name = "stapler", .Price = 5.09}
さらに重要なのは、名前付き型のインスタンスには適用されない匿名型の使用に制限があることです。
firstProd2
、 secondProd2
、および thirdProd2
は、同じ匿名型のインスタンスです。 ただし、共有匿名型の名前は使用できず、コード内の型名が必要な場所には表示できません。 たとえば、匿名型を使用してメソッド シグネチャを定義したり、別の変数やフィールドを宣言したり、任意の型宣言に使用したりすることはできません。 そのため、メソッド間で情報を共有する必要がある場合、匿名型は適切ではありません。
匿名型の定義
匿名型のインスタンスの宣言に応答して、コンパイラは、指定されたプロパティを含む新しいクラス定義を作成します。
匿名型に少なくとも 1 つのキー プロパティが含まれている場合、定義は Object から継承された 3 つのメンバー ( Equals、 GetHashCode、 ToString) をオーバーライドします。 等価性をテストし、ハッシュ コード値を決定するために生成されたコードでは、キー プロパティのみが考慮されます。 匿名型にキー プロパティが含まれている場合は、 ToString のみがオーバーライドされます。 匿名型の明示的な名前付きプロパティは、これらの生成されたメソッドと競合できません。 つまり、 .Equals
、 .GetHashCode
、または .ToString
を使用してプロパティに名前を付けることはできません。
少なくとも 1 つのキー プロパティを持つ匿名型定義では、 System.IEquatable<T> インターフェイスも実装されます。ここで、 T
は匿名型の型です。
コンパイラによって作成されるコードとオーバーライドされたメソッドの機能の詳細については、「 匿名型定義」を参照してください。
こちらも参照ください
.NET