支持 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 Infer
为 On
或 Off
,则会发生类型推理。 如果 Option Infer
为 Off
且 Option Strict
为 On
,则发生编译时错误。
' 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
的类,该类具有公共 Name
和 Phone
属性以及其他属性,则可以采用以下方式使用对象初始值设定项:
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> 的其他扩展包括 Count、Union 和 Intersect。
下面的扩展方法向 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 表达式来捕获基本查询方法(如 Where
、Select
、Order By
、Take 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 表达式。