支持 LINQ 的 Visual Basic 功能

语言集成查询 (LINQ) 的名称是指 Visual Basic 中的技术,该技术直接在语言中支持查询语法和其他语言结构。 使用 LINQ,无需学习新语言即可针对外部数据源进行查询。 可使用 Visual Basic 对关系数据库、XML 存储或对象中的数据进行查询。 将查询功能集成到语言中,可以在编译时检查语法错误和类型安全。 此集成还可确保你已经了解在 Visual Basic 中编写丰富多样的查询所需的大部分知识。

以下部分详细介绍了支持 LINQ 的语言结构,足以帮助你开始阅读介绍性文档、代码示例和示例应用程序。 你还可以单击链接,查找有关语言功能如何集成以实现语言集成查询的更详细说明。 演练:在 Visual Basic 中编写查询是一个不错的起点。

查询表达式

Visual Basic 中的查询表达式可以用类似于 SQL 或 XQuery 的声明性语法来表示。 在编译时,查询语法转换为对 LINQ 提供程序的标准查询运算符扩展方法实现的方法调用。 应用程序通过使用 Imports 语句指定适当的命名空间,来控制范围内的标准查询运算符。 Visual Basic 查询表达式的语法如下所示:

Dim londonCusts = From cust In customers
                  Where cust.City = "London"
                  Order By cust.Name Ascending
                  Select cust.Name, cust.Phone

有关详细信息,请参阅Visual Basic 中的 LINQ 简介

隐式类型化变量

可以启用编译器推断并分配类型,而不必在声明并初始化变量时显式指定类型。 这称为“局部类型推理”。

推断出类型的变量与显式指定其类型的变量一样都是强类型。 仅当在方法体中定义本地变量时,局部类型推理才有效。 有关详细信息,请参阅 Option Infer 语句本地类型推理

下面的示例阐释了局部类型推理。 若要使用此示例,必须将 Option Infer 设置为 On

' The variable aNumber will be typed as an integer.
Dim aNumber = 5

' The variable aName will be typed as a String.
Dim aName = "Virginia"

局部类型推理还可以实现创建匿名类型(本节稍后将对此进行介绍),这对于 LINQ 查询是必需的。

在下面的 LINQ 示例中,如果 Option InferOnOff,则会发生类型推理。 如果 Option InferOffOption StrictOn,则发生编译时错误。

' Query example.
' If numbers is a one-dimensional array of integers, num will be typed
' as an integer and numQuery will be typed as IEnumerable(Of Integer)--
' basically a collection of integers.

Dim numQuery = From num In numbers
               Where num Mod 2 = 0
               Select num

对象初始值设定项

如果必须创建匿名类型才能保存查询结果,则可在查询表达式中使用对象初始值设定项。 对象初始值设定项还可用于在查询之外初始化命名类型的对象。 通过使用对象初始值设定项,你可以在单个行中初始化对象,而无需显式调用构造函数。 假设你有一个名为 Customer 的类,该类具有公共 NamePhone 属性以及其他属性,则可以采用以下方式使用对象初始值设定项:

Dim aCust = New Customer With {.Name = "Mike",
                               .Phone = "555-0212"}

有关详细信息,请参阅对象初始值设定项:命名类型和匿名类型

匿名类型

匿名类型提供了一种简便的方法,可将一组属性暂时分组到要包含在查询结果中的元素中。 这样,你可以按任意顺序在查询中选择可用字段的任意组合,而无需为元素定义命名的数据类型。

“匿名类型”由编译器动态构造。 该类型的名称由编译器分配,且名称可能会随每个新的编译而更改。 因此,不能直接使用该名称。 匿名类型的初始化方式如下:

' Outside a query.
Dim product = New With {.Name = "paperclips", .Price = 1.29}

' Inside a query.
' You can use the existing member names of the selected fields, as was
' shown previously in the Query Expressions section of this topic.
Dim londonCusts1 = From cust In customers
                   Where cust.City = "London"
                   Select cust.Name, cust.Phone

' Or you can specify new names for the selected fields.
Dim londonCusts2 = From cust In customers
                   Where cust.City = "London"
                   Select CustomerName = cust.Name,
                   CustomerPhone = cust.Phone

有关详细信息,请参阅匿名类型

扩展方法

使用扩展方法,可以将方法添加到定义之外的数据类型或接口。 实际上,利用此功能,可以将新方法添加到现有类型,而不会实际修改类型。 标准查询运算符本身是一组扩展方法,它们为实现 IEnumerable<T> 的任何类型提供 LINQ 查询功能。 IEnumerable<T> 的其他扩展包括 CountUnionIntersect

下面的扩展方法向 String 类添加一个 print 方法。

' Import System.Runtime.CompilerServices to use the Extension attribute.
<Extension()>
Public Sub Print(ByVal str As String)
    Console.WriteLine(str)
End Sub

调用方法的方式类似于 String 的普通实例方法:

Dim greeting As String = "Hello"
greeting.Print()

有关详细信息,请参阅扩展方法

Lambda 表达式

Lambda 表达式是没有名称的函数,用于计算并返回单个值。 与命名函数不同,Lambda 表达式可以同时定义和执行。 下面的示例将显示 4。

Console.WriteLine((Function(num As Integer) num + 1)(3))

可以将 Lambda 表达式定义分配给变量名,然后使用该名称调用该函数。 下面的示例也显示 4。

Dim add1 = Function(num As Integer) num + 1
Console.WriteLine(add1(3))

在 LINQ 中,Lambda 表达式是许多标准查询运算符的基础。 编译器创建 Lambda 表达式来捕获基本查询方法(如 WhereSelectOrder ByTake While 等)中定义的计算。

例如,以下代码定义了一个查询,该查询返回学生列表中所有高年级学生。

Dim seniorsQuery = From stdnt In students
                   Where stdnt.Year = "Senior"
                   Select stdnt

查询定义编译为类似于以下的示例代码,该示例使用两个 Lambda 表达式来指定 WhereSelect 的参数。

Dim seniorsQuery2 = students.
    Where(Function(st) st.Year = "Senior").
    Select(Function(s) s)

任一版本都可以使用 For Each 循环运行:

For Each senior In seniorsQuery
    Console.WriteLine(senior.Last & ", " & senior.First)
Next

有关详细信息,请参阅 Lambda 表达式

另请参阅