演练:用 Visual Basic 编写查询

本演练展示如何使用 Visual Basic 语言功能编写语言集成查询 (LINQ) 查询表达式。 本演练演示如何对“学生”对象列表创建查询、如何运行查询以及如何修改查询。 查询包含多个功能,包括对象初始值设定项、本地类型推断和匿名类型。

完成本演练后,你就可以继续查看自己感兴趣的特定 LINQ 提供程序的示例和文档。 LINQ 提供程序包括 LINQ to SQL、LINQ to DataSet 和 LINQ to XML。

创建项目

创建控制台应用程序项目

  1. 启动 Visual Studio。

  2. “文件” 菜单上,指向 “新建” ,然后单击 “项目”

  3. 在“已安装的模板”列表中单击“Visual Basic”。

  4. 在项目类型列表中,单击“控制台应用程序”。 在“名称”框中,键入项目名称,然后单击“确定”。

    这样就创建了一个项目。 默认情况下,它包含对 System.Core.dll 的引用。 此外,项目设计器 ->“引用”页 (Visual Basic) 上的“导入的命名空间”列表中包括 System.Linq 命名空间。

  5. “编译”页的“项目设计器 (Visual Basic)”中,确保“Option infer”设置为“打开”。

添加内存中的数据源

此演练中的查询的数据源是 Student 对象列表。 每个 Student 对象都包含名字、姓氏、年级以及在全体学生中的学业排名。

添加数据源

  • 定义 Student 类,并创建类的实例的列表。

    重要

    如何:创建项列表中提供了定义 Student 类以及创建在本演练示例中使用的列表所需的代码。 可以从中复制代码并粘贴在自己的项目中。 新代码将替换在创建项目时显示的代码。

向学生列表添加新学生

创建查询

执行时,此部分中添加的查询将生成学业排名前十的学生列表。 由于查询每次都选择完整 Student 的对象,因此查询结果的类型为 IEnumerable(Of Student)。 但是,查询定义中通常不指定查询的类型。 而是由编译器使用本地类型推断来确定该类型。 有关详细信息,请参阅本地类型推断。 查询的范围变量 currentStudent 用作对源 students 中每个 Student 实例的引用,提供对 students 中每个对象的属性的访问。

创建简单查询

  1. 在项目的 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
    
  2. 将鼠标指针悬停在代码中的 studentQuery 上,验证编译器分配的类型是否为 IEnumerable(Of Student)

运行查询

变量 studentQuery 包含查询的定义,而不是运行查询的结果。 用于运行查询的一种典型机制就是 For Each 循环。 通过循环迭代变量,可访问返回的序列中的每个元素。 有关查询执行的详细信息,请参阅编写你的第一个 LINQ 查询

运行查询

  1. 在项目中的查询下添加以下 For Each 循环。

    For Each studentRecord In studentQuery
        Console.WriteLine(studentRecord.Last & ", " & studentRecord.First)
    Next
    
  2. 将鼠标指针悬停在循环控制变量 studentRecord 上以查看其数据类型。 studentRecord 的类型被推断为 Student,因为studentQuery 返回 Student 实例的集合。

  3. 按 CTRL + F5 生成并运行应用程序。 请注意控制台窗口中的结果。

修改查询

如果查询结果按指定顺序排列,则会更容易扫描。 可以基于任何可用字段对返回的序列进行排序。

对结果进行排序

  1. 在查询的 Where 语句和 Select 语句之间添加以下 Order By 子句。 Order By子句会根据每个学生的姓氏从 A 到 Z 的顺序对结果进行排序。

    Order By currentStudent.Last Ascending
    
  2. 若要按姓氏再按名字排序,请将这两个字段添加到查询中:

    Order By currentStudent.Last Ascending, currentStudent.First Ascending
    

    还能指定 Descending 以采用从 Z 到 A 的顺序。

  3. 按 CTRL + F5 生成并运行应用程序。 请注意控制台窗口中的结果。

引入本地标识符

  1. 添加此部分中的代码,以在查询表达式中引入本地标识符。 本地标识符将保存中间结果。 在下面的示例中,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
    
  2. 按 CTRL + F5 生成并运行应用程序。 请注意控制台窗口中的结果。

在 Select 子句中投影一个字段

  1. 添加此部分中的查询和 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
    
  2. 将鼠标指针悬停在代码中的 studentQuery3 上,验证分配的类型是否为 IEnumerable(Of String)

  3. 按 CTRL + F5 生成并运行应用程序。 请注意控制台窗口中的结果。

在 Select 子句中创建匿名类型

  1. 添加此部分中的代码,了解如何在查询中使用匿名类型。 如果希望从数据源返回多个字段而不是完整的记录(上文示例中的 currentStudent 记录)或单个字段(前文中的 First)时,可以在查询中使用它们。 可以在 Select 子句中指定字段,而不是定义一个新的命名类型(其中包含你想要包括在结果中的字段),而编译器会创建一个匿名类型,并将这些字段作为其属性。 有关详细信息,请参阅匿名类型

    下面的示例创建一个查询,该查询返回学业排名在 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
    
  2. 按 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 提供程序的文档和示例:

另请参阅