【vs.net 2008系列-LINQ】 4.查询操作中的类型关系 (Visual Basic)
语言集成查询 (LINQ) 查询操作中使用的变量是强类型的,因而必须互相兼容。在数据源、查询本身及查询执行中都使用强类型。下图标识用于描述 LINQ 查询的术语。有关查询的各部分的更多信息,请参见基本查询操作 (Visual Basic)。
查询中范围变量的类型必须与数据源中元素的类型兼容。查询变量的类型必须与 Select 子句中定义的序列元素兼容。最后,序列元素的类型也必须与执行查询的 For Each 语句中使用的循环控制变量的类型兼容。此强类型便于在编译时识别类型错误。
Visual Basic 2008 通过实现局部类型推断(又称为“隐式类型”)使强类型变得方便使用。在上一个示例中就使用了该功能,并且您将看到在所有 LINQ 示例和文档中都使用了该功能。在 Visual Basic 中,只需使用 Dim 语句,而无需 As 子句即可实现局部类型推断。在下面的示例中,city 被强类型化为字符串。
|
Visual Basic
|
Dim city = "Seattle" |
说明: |
|---|
|
仅当 Option Infer 设置为 On 时,局部类型推断才有效。有关更多信息,请参见 Option Infer 语句。 |
但是,即使您在查询中使用局部类型推断,在数据源中的变量、查询变量和查询执行循环中也存在相同的类型关系。当您编写 LINQ 查询或使用文档中的示例和代码示例时,对这些类型关系有一个基本了解很有用。
返回源数据的整个元素的查询 下面的示例演示返回从源数据选择的元素序列的 LINQ 查询操作。源 names 包含一个字符串数组,而查询输出是一个包含以字母 M 开头的字符串的序列。
|
Visual Basic
|
Dim names = New String() {"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 中优先采用的一种方式。
|
Visual Basic
|
Dim names2() As String = {"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 也是一个字符串。
返回所选元素的一个字段的查询 下面的示例演示一个 LINQ to SQL 查询操作,该操作返回只包含从数据源选择的每个元素的一部分的序列。此查询将 Customer 对象的集合作为其数据源,并只将 Name 属性投影在结果中。因为客户姓名是一个字符串,所以此查询生成一个字符串序列作为输出。
|
Visual Basic
|
' 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 也将是 IEnumerable(Of String),而不是 Customer。
-
因为 custNames 表示一个字符串序列,所以 For Each 循环的迭代变量 custName 必须是一个字符串。
如果不使用局部类型推断,上一个示例将很难编写和理解,如下面的示例所示。
|
Visual Basic
|
' 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 |
需要匿名类型的查询 下面的示例演示更复杂的情况。在上一个示例中,为所有变量显式指定类型不是很方便。在此示例中,则根本不可能。此查询中的 Select 子句不选择数据源中的整个 Customer 元素,或每个元素的单个字段,而是返回原始 Customer 对象的两个属性:Name 和 City。为了响应 Select 子句,编译器将定义包含这两个属性的匿名类型。在 For Each 循环中执行 nameCityQuery 的结果是新匿名类型的实例集合。因为匿名类型没有可用的名称,所以您无法显式指定 nameCityQuery 或 custInfo 的类型。也就是说,使用匿名类型,没有可用的类型名称来代替 IEnumerable(Of String) 中的 String。有关更多信息,请参见匿名类型。
|
Visual Basic
|
' 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 中创建的匿名类型。因为此类型没有可用的名称,所以必须隐式确定循环迭代变量的类型。
说明:
浙公网安备 33010602011771号