演练:用 Visual Basic 编写查询
本演练演示了如何使用 Visual Basic 语言功能来编写 语言集成查询 (LINQ) 查询表达式。本演练演示如何对一个 Student 对象列表创建查询、如何运行以及如何修改这些查询。这些查询加入了 Visual Basic 2008 中的多项新功能,包括对象初始值设定项、局部类型推理和匿名类型。
完成本演练后,就可以转到所关注的特定 LINQ 提供程序的示例和文档。LINQ 提供程序包括 LINQ to SQL、LINQ to DataSet 和 LINQ to XML。
创建项目
创建控制台应用程序项目
启动 Visual Studio。
在**“文件”菜单上指向“新建”,再单击“项目”**。
在**“已安装的模板”列表中,单击“Visual Basic”**。
在应用程序类型列表中,单击**“控制台应用程序”。在“名称”框中键入项目的名称,然后单击“确定”**。
随即创建一个项目。默认情况下,此项目包含对 System.Core.dll 的引用。此外,项目设计器 ->“引用”页 (Visual Basic) 上的**“导入的命名空间”**列表中还包括 System.Linq 命名空间。
在 “项目设计器”->“编译”页 (Visual Basic),请确保 option infer 设置为。
添加内存中数据源
本演练中查询的数据源是 Student 对象列表。每个 Student 对象都包含名、姓、年级和在全体学生中的学习名次。
添加数据源
定义 Student 类,然后创建该类的实例列表。
重要事项 如何:创建项列表中提供了定义 Student 类和创建演练示例所使用的列表所需的代码。您可以复制这些代码并将其粘贴到您的项目中。新代码用于替换在您创建项目时显示的代码。
在学生列表中添加新学生
- 按照 getStudents 方法中的模式将 Student 类的另一个实例添加到列表中。添加学生涉及到对象初始值设定项。有关更多信息,请参见对象初始值设定项:命名类型和匿名类型 (Visual Basic)。
创建查询
执行本节添加的查询时,将生成学习名次位于前十位的学生列表。由于查询每次都选择整个 Student 对象,因此查询结果的类型是 IEnumerable(Of Student)。但是,查询的类型通常不在查询定义中指定,而是由编译器使用局部类型推理来确定。有关更多信息,请参见局部类型推理 (Visual Basic)。查询的范围变量 currentStudent 用作对源 (students) 中每个 Student 实例的引用,以提供对 students 中每个对象属性的访问。
创建简单查询
在项目的 Main 方法中找到带如下标记的位置:
' ****Paste query and query execution code from the walkthrough, ' ****or any code of your own, here in Main.
将下面的代码复制并粘贴到此位置。
Dim studentQuery = From currentStudent In students Where currentStudent.Rank <= 10 Select currentStudent
将鼠标指针停留在代码中的 studentQuery 上,以验证编译器指定的类型是否为 IEnumerable(Of Student)。
运行查询
变量 studentQuery 包含查询的定义,而非运行查询的结果。运行查询的典型机制是 For Each 循环。通过循环迭代变量来访问返回序列中的每个元素。有关查询执行的更多信息,请参见编写第一个 LINQ 查询 (Visual Basic)。
运行查询
将下面的 For Each 循环添加到项目中的查询下面。
For Each studentRecord In studentQuery Console.WriteLine(studentRecord.Last & ", " & studentRecord.First) Next
将鼠标指针停留在循环控制变量 studentRecord 上,以查看其数据类型。studentRecord 类型被推断为 Student,因为 studentQuery 返回 Student 实例的集合。
按 CTRL+F5 生成并运行该应用程序。注意控制台窗口中的结果。
修改查询
如果结果按指定顺序排列,则浏览查询结果会更容易。您可以根据任何可用字段对返回的序列进行排序。
对结果进行排序
将下面的 Order By 子句添加到查询的 Where 语句和 Select 语句之间。Order By 子句将根据每个学生的姓按从 A 到 Z 的字母顺序对结果进行排序。
Order By currentStudent.Last Ascending
若要先按姓再按名进行排序,请将两个字段都添加到查询:
Order By currentStudent.Last Ascending, currentStudent.First Ascending
您也可以指定 Descending,以便按从 Z 到 A 的顺序排序。
按 CTRL+F5 生成并运行该应用程序。注意控制台窗口中的结果。
引入本地标识符
添加本节中的代码,将本地标识符引入查询表达式。该本地标识符将保存中间结果。在下面的示例中,name 是保存学生姓和名的串联的标识符。本地标识符可以提供方便,也可以通过存储表达式的结果来避免多次计算,从而提高性能。
Dim studentQuery2 = From currentStudent In students Let name = currentStudent.Last & ", " & currentStudent.First Where currentStudent.Year = "Senior" And currentStudent.Rank <= 10 Order By name Ascending Select currentStudent ' If you see too many results, comment out the previous ' For Each loop. For Each studentRecord In studentQuery2 Console.WriteLine(studentRecord.Last & ", " & studentRecord.First) Next
按 CTRL+F5 生成并运行该应用程序。注意控制台窗口中的结果。
在 Select 子句中投影一个字段
添加本节中的查询和 For Each 循环以创建一个查询,该查询将生成一个其元素与源中元素不同的序列。在下面的示例中,源是 Student 对象的集合,但是只返回每个对象的一个成员:姓氏为 Garcia 的学生的名字。由于 currentStudent.First 是一个字符串,因此 studentQuery3 返回的序列的数据类型是 IEnumerable(Of String),为字符串序列。如前面的示例所示,studentQuery3 数据类型的分配由编译器使用局部类型推理来确定。
Dim studentQuery3 = From currentStudent In students Where currentStudent.Last = "Garcia" Select currentStudent.First ' If you see too many results, comment out the previous ' For Each loops. For Each studentRecord In studentQuery3 Console.WriteLine(studentRecord) Next
将鼠标指针停留在代码中的 studentQuery3 上,以验证分配的类型是否为 IEnumerable(Of String)。
按 CTRL+F5 生成并运行该应用程序。注意控制台窗口中的结果。
在 Select 子句中创建匿名类型
添加本节中的代码以了解在查询中如何使用匿名类型。当您希望从数据源返回多个字段而不是返回完整记录(前面示例中的 currentStudent 记录)或单个字段(前一节中的 First)时,可以在查询中使用匿名类型。而不是定义包含字段要包含在结果中的新命名类型,可以在 Select 子句指定字段,并且编译器使用这些字段创建匿名类型作为其属性。有关更多信息,请参见匿名类型 (Visual Basic)。
下面的示例创建一个查询,返回学习名次位于 1 和 10 之间的高年级学生的姓名和学习名次,并按学习名次排序。在本例中,必须推断 studentQuery4 的类型,因为 Select 子句返回匿名类型的实例,而匿名类型没有可用的名称。
Dim studentQuery4 = From currentStudent In students Where currentStudent.Year = "Senior" And currentStudent.Rank <= 10 Order By currentStudent.Rank Ascending Select currentStudent.First, currentStudent.Last, currentStudent.Rank ' If you see too many results, comment out the previous ' For Each loops. For Each studentRecord In studentQuery4 Console.WriteLine(studentRecord.Last & ", " & studentRecord.First & ": " & studentRecord.Rank) Next
按 CTRL+F5 生成并运行该应用程序。注意控制台窗口中的结果。
其他示例
现在您已经了解了基础知识,接下来是一组演示 LINQ 查询的灵活性和强大功能的其他示例。每个示例之前有描述其用途的简要说明。停留在查询结果变量的鼠标指针每个查询的查看推断的类型。使用一个 For Each 循环生成结果。
' Find all students who are seniors.
Dim q1 = From currentStudent In students
Where currentStudent.Year = "Senior"
Select currentStudent
' Write a For Each loop to execute the query.
For Each q In q1
Console.WriteLine(q.First & " " & q.Last)
Next
' Find all students with a first name beginning with "C".
Dim q2 = From currentStudent In students
Where currentStudent.First.StartsWith("C")
Select currentStudent
' Find all top ranked seniors (rank < 40).
Dim q3 = From currentStudent In students
Where currentStudent.Rank < 40 And currentStudent.Year = "Senior"
Select currentStudent
' Find all seniors with a lower rank than a student who
' is not a senior.
Dim q4 = From student1 In students, student2 In students
Where student1.Year = "Senior" And student2.Year <> "Senior" And
student1.Rank > student2.Rank
Select student1
Distinct
' Retrieve the full names of all students, sorted by last name.
Dim q5 = From currentStudent In students
Order By currentStudent.Last
Select Name = currentStudent.First & " " & currentStudent.Last
' Determine how many students are ranked in the top 20.
Dim q6 = Aggregate currentStudent In students
Where currentStudent.Rank <= 20
Into Count()
' Count the number of different last names in the group of students.
Dim q7 = Aggregate currentStudent In students
Select currentStudent.Last
Distinct
Into Count()
' Create a list box to show the last names of students.
Dim lb As New System.Windows.Forms.ListBox
Dim q8 = From currentStudent In students
Order By currentStudent.Last
Select currentStudent.Last Distinct
For Each nextName As String In q8
lb.Items.Add(nextName)
Next
' Find every process that has a lowercase "h", "l", or "d" in its name.
Dim letters() As String = {"h", "l", "d"}
Dim q9 = From proc In System.Diagnostics.Process.GetProcesses,
letter In letters
Where proc.ProcessName.Contains(letter)
Select proc
For Each proc In q9
Console.WriteLine(proc.ProcessName & ", " & proc.WorkingSet64)
Next
其他信息
熟悉使用查询的基本概念之后,就可以开始阅读所关注的特定类型的 LINQ 提供程序的文档和示例:
请参见
任务
概念
对象初始值设定项:命名类型和匿名类型 (Visual Basic)