支持 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 InferOn.

' 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 InferOff 分别为 Option 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 类。

' 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 表达式来指定 Where 参数和 Select参数。

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 表达式

另请参阅