Language-Integrated クエリ (LINQ) クエリ操作で使用される変数は厳密に型指定されており、相互に互換性がある必要があります。 厳密な型指定は、データ ソース、クエリ自体、およびクエリ実行で使用されます。 次の図は、LINQ クエリの説明に使用される用語を示しています。 クエリの各部分の詳細については、「 基本的なクエリ操作 (Visual Basic)」を参照してください。
クエリ内の範囲変数の型は、データ ソース内の要素の型と互換性がある必要があります。 クエリ変数の型は、 Select
句で定義されているシーケンス要素と互換性がある必要があります。 最後に、シーケンス要素の型は、クエリを実行する For Each
ステートメントで使用されるループ制御変数の型と互換性がある必要もあります。 この厳密な型指定により、コンパイル時の型エラーの識別が容易になります。
Visual Basic では、ローカル型推論 (暗黙的な型指定とも呼ばれます) を実装することで、厳密 な型指定が便利になります。 この機能は前の例で使用されており、LINQ のサンプルとドキュメント全体で使用されています。 Visual Basic では、ローカル型の推論は、As
句のないDim
ステートメントを使用するだけで実現されます。 次の例では、 city
は文字列として厳密に型指定されています。
Dim city = "Seattle"
注
ローカル型推論は、 Option Infer
が On
に設定されている場合にのみ機能します。 詳細については、「 Option Infer ステートメント」を参照してください。
ただし、クエリでローカル型推論を使用する場合でも、データ ソース内の変数、クエリ変数、およびクエリ実行ループの間には、同じ型リレーションシップが存在します。 LINQ クエリを記述する場合や、ドキュメントのサンプルとコード例を使用する場合は、これらの型リレーションシップの基本的な理解を深めると便利です。
データ ソースから返される型と一致しない範囲変数に明示的な型を指定することが必要な場合があります。 範囲変数の型は、 As
句を使用して指定できます。 ただし、変換が 縮小 変換で、 Option Strict
が On
に設定されている場合は、エラーが発生します。 そのため、データ ソースから取得した値に対して変換を実行することをお勧めします。
Cast メソッドを使用して、データ ソースの値を明示的な範囲変数型に変換できます。
Select
句で選択した値を、範囲変数の型とは異なる明示的な型にキャストすることもできます。 これらの点を次のコードに示します。
Dim numbers1() As Integer = {1, 2, 4, 16, 32, 64}
Dim numbers2() As Double = {5.0#, 10.0#, 15.0#}
' This code does not result in an error.
Dim numberQuery1 = From n As Integer In numbers1 Where n > 5
' This code results in an error with Option Strict set to On. The type Double
' cannot be implicitly cast as type Integer.
Dim numberQuery2 = From n As Integer In numbers2 Where n > 5
' This code casts the values in the data source to type Integer. The type of
' the range variable is Integer.
Dim numberQuery3 = From n In numbers2.Cast(Of Integer)() Where n > 5
' This code returns the value of the range variable converted to Integer. The type of
' the range variable is Double.
Dim numberQuery4 = From n In numbers2 Where n > 5 Select CInt(n)
ソース データの要素全体を返すクエリ
次の例は、ソース データから選択された要素のシーケンスを返す LINQ クエリ操作を示しています。 ソース ( names
) には文字列の配列が含まれており、クエリ出力は文字 M で始まる文字列を含むシーケンスです。
Dim names = {"John", "Rick", "Maggie", "Mary"}
Dim mNames = From name In names
Where name.IndexOf("M") = 0
Select name
For Each nm In mNames
Console.WriteLine(nm)
Next
これは次のコードと同じですが、はるかに短く、簡単に記述できます。 Visual Basic では、クエリでのローカル型の推論への依存が推奨されるスタイルです。
Dim names2 = {"John", "Rick", "Maggie", "Mary"}
Dim mNames2 As IEnumerable(Of String) =
From name As String In names
Where name.IndexOf("M") = 0
Select name
For Each nm As String In mNames
Console.WriteLine(nm)
Next
次のリレーションシップは、型が暗黙的に決定されるか明示的に決定されるかに関係なく、前のコード例の両方に存在します。
データ ソースの要素の型 (
names
) は、クエリ内の範囲変数name
の型です。選択したオブジェクトの型 (
name
) によって、クエリ変数の型 (mNames
) が決まります。 ここでname
は文字列であるため、クエリ変数は Visual Basic の IEnumerable(Of String) です。mNames
で定義されたクエリは、For Each
ループで実行されます。 このループは、クエリの実行結果を反復処理します。mNames
、それが実行されると文字列のシーケンスを返すので、ループ反復変数nm
も文字列です。
選択した要素から 1 つのフィールドを返すクエリ
次の例は、データ ソースから選択された各要素の 1 つの部分のみを含むシーケンスを返す LINQ to SQL クエリ操作を示しています。 クエリは、 Customer
オブジェクトのコレクションをデータ ソースとして受け取り、結果の Name
プロパティのみを投影します。 顧客名は文字列であるため、クエリは文字列のシーケンスを出力として生成します。
' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim custNames = From cust In customers
Where cust.City = "London"
Select cust.Name
For Each custName In custNames
Console.WriteLine(custName)
Next
変数間のリレーションシップは、より単純な例のようなものです。
データ ソースの要素の型 (
customers
) は、クエリ内の範囲変数cust
の型です。 この例では、その型はCustomer
。Select
ステートメントは、オブジェクト全体ではなく、各Customer
オブジェクトのName
プロパティを返します。Name
は文字列であるため、クエリ変数custNames
は、Customer
ではなく IEnumerable(Of String) になります。custNames
は文字列のシーケンスを表すので、For Each
ループの反復変数 (custName
) は文字列である必要があります。
ローカル型の推論がない場合、次の例に示すように、前の例では書き込みと理解が煩雑になります。
' Method GetTable returns a table of Customer objects.
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)()
Dim custNames As IEnumerable(Of String) =
From cust As Customer In customers
Where cust.City = "London"
Select cust.Name
For Each custName As String In custNames
Console.WriteLine(custName)
Next
匿名型を必要とするクエリ
次の例は、より複雑な状況を示しています。 前の例では、すべての変数の型を明示的に指定するのは不便でした。 この例では不可能です。 データ ソースから Customer
要素全体、または各要素から 1 つのフィールドを選択する代わりに、このクエリの Select
句は、元の Customer
オブジェクトの 2 つのプロパティ ( Name
と City
) を返します。
Select
句に応答して、コンパイラはこれら 2 つのプロパティを含む匿名型を定義します。
For Each
ループでnameCityQuery
を実行した結果は、新しい匿名型のインスタンスのコレクションです。 匿名型には使用可能な名前がないため、 nameCityQuery
の型や custInfo
を明示的に指定することはできません。 つまり、匿名型では、IEnumerable(Of String)
のString
の代わりに使用する型名はありません。 詳細については、「 匿名型」を参照してください。
' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim nameCityQuery = From cust In customers
Where cust.City = "London"
Select cust.Name, cust.City
For Each custInfo In nameCityQuery
Console.WriteLine(custInfo.Name)
Next
前の例のすべての変数に型を指定することはできませんが、リレーションシップは変わりません。
データ ソース内の要素の型は、クエリ内の範囲変数の型です。 この例では、
cust
はCustomer
のインスタンスです。Select
ステートメントは匿名型を生成するため、クエリ変数nameCityQuery
は匿名型として暗黙的に型指定する必要があります。 匿名型には使用可能な名前がないため、明示的に指定することはできません。For Each
ループ内の反復変数の型は、手順 2 で作成した匿名型です。 この型には使用可能な名前がないため、ループ反復変数の型を暗黙的に決定する必要があります。
こちらも参照ください
- Visual Basic での LINQ の概要
- 匿名型
- ローカル型推論
- Visual Basic での LINQ の概要
- LINQ
- クエリ
.NET