LINQ 要点

上一篇


参考资料

💡 建议

  • 内容建议完整学习;
  • 内容可以根据需要学习。

要点

  • 所有 LINQ 查询操作都由以下三个不同的操作组成:

    1. 获取数据源
    2. 创建查询
    3. 执行查询
    csharp 复制代码
    /**
     * 为方便起见,此示例将一个整数数组用作数据源;
     * 但其中涉及的概念同样适用于其他数据源
     */
     
    // 1. 获取数据源
    int[] numbers = [ 0, 1, 2, 3, 4, 5, 6 ];
    
    // 2. 创建查询
    // numQuery 是一个 IEnumerable<int>
    var numQuery = from num in numbers
                   where (num % 2) == 0
                   select num;
    
    // 3. 执行查询
    foreach (int num in numQuery)
    {
        Console.Write("{0,1} ", num);
    }
    
    /**
     * 此查询从整数数组中返回所有偶数。
     * 查询表达式包含三个子句:from、where 和 select。
     * from 子句指定数据源;
     * where 子句应用筛选器;
     * select 子句指定返回元素的类型。
     */
  • 只有在循环访问查询变量后,才会执行查询 (例如,在 foreach 语句中或对其 IEnumerator.MoveNext() 方法的直接调用)。 有关详细信息,请参阅 LINQ 查询简介

  • 查询表达式中的变量全都是强类型 ,尽管在许多情况下,无需显式提供类型,因为编译器可以推断出。有关详细信息,请参阅 LINQ 查询操作中的类型关系

  • 在编译时,查询表达式根据 C# 规范规则转换成标准查询运算符方法调用。 可使用查询语法表示的任何查询都可以使用方法语法进行表示。 不过,在大多数情况下,查询语法的可读性更高,也更为简洁。 有关详细信息,请参阅 C# 语言规范标准查询运算符概述

  • 查询存储在查询变量中,并用查询表达式进行初始化。你使用 C# 查询语法来编写查询。

  • 标准查询运算符按执行方式可分为两类:立即执行延迟执行 。使用延迟执行的查询运算符可以进一步分为两种类别:流式处理非流式处理 。具体的按照执行方式对每个标准查询运算符方法进行分类的情况请参阅 分类表

    ✡️ 重要

    此条要点建议点击所有的外部链接详细查看

  • 查询基本上是针对如何检索和组织数据的一套说明。当请求结果中的每个后续项目时,查询将延迟执行。使用 foreach 循环访问结果时,项将在受到访问时返回。若要在不执行 foreach 循环的情况下对查询求值并存储其结果,只需调用查询变量上的以下方法之一:

  • 在存储查询结果时,应将返回的集合对象分配给一个新变量,如下面的示例所示:

    csharp 复制代码
    List<int> numbers = [ 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 ];
    
    IEnumerable<int> queryFactorsOfFour = from num in numbers
                                          where num % 4 == 0
                                          select num;
    
    // 在新变量中存储查询结果
    // 未执行 foreach 循环
    var factorsofFourList = queryFactorsOfFour.ToList();
    
    // 对新创建的列表进行读写操作,证明其持有数据
    Console.WriteLine(factorsofFourList[2]);
    factorsofFourList[2] = 0;
    Console.WriteLine(factorsofFourList[2]);
  • 查询表达式必须以 from 子句开头,且必须以 selectgroup 子句结尾 。在第一个 from 子句与最后一个 selectgroup 子句之间,可以包含以下这些可选子句中的一个或多个:whereorderbyjoinlet,甚至是其他 from 子句。还可以使用 into 关键字启用 joingroup 子句的结果,作为同一查询表达式中更多查询子句的源。

    csharp 复制代码
    // 数据源
    int[] scores = [90, 71, 82, 93, 75, 82];
    
    // 查询表达式
    IEnumerable<int> scoreQuery = // 查询变量
        from score in scores // 必须以 from 子句开头
        where score > 80 // 筛选子句(可选的)
        orderby score descending // 排序子句(可选的)
        select score; // 必须以 select 或 group 子句结尾
    
    // 执行查询以生成结果
    foreach (var testScore in scoreQuery)
    {
        Console.WriteLine(testScore);
    }
    
    // 输出:93 90 82 82
  • 上一个示例中,scoreQuery 是一个 查询变量 ,有时仅被称作 查询 。查询变量不存储在 foreach 循环生成中的任何实际结果数据。并且当 foreach 语句执行时,查询结果不会通过查询变量 scoreQuery 返回;而是通过迭代变量 testScore 返回。可以在第二个 foreach 循环中迭代 scoreQuery 变量。只要既没有修改它,也没有修改数据源,便会生成相同结果。

  • 查询变量可以存储采用查询语法、方法语法或是两者的组合进行表示的查询。在以下示例中,queryMajorCitiesqueryMajorCities2 都是查询变量:

    csharp 复制代码
    City[] cities = [
        new City("Tokyo", 37_833_000),
        new City("Delhi", 30_290_000),
        new City("Shanghai", 27_110_000),
        new City("São Paulo", 22_043_000)
    ];
    
    // 查询语法
    IEnumerable<City> queryMajorCities =
        from city in cities
        where city.Population > 30_000_000
        select city;
    
    // 执行查询以生成结果
    foreach (City city in queryMajorCities)
    {
        Console.WriteLine(city);
    }
    
    // 输出:
    // City { Name = Tokyo, Population = 37833000 }
    // City { Name = Delhi, Population = 30290000 }
    
    // 方法语法
    IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 30_000_000);
    
    // 执行查询以生成结果
    foreach (City city in queryMajorCities2)
    {
        Console.WriteLine(city);
    }
    
    // 输出:
    // City { Name = Tokyo, Population = 37833000 }
    // City { Name = Delhi, Population = 30290000 }
  • 另一方面,以下两个示例演示不是查询变量的变量(即使各自使用查询进行初始化)。它们不是查询变量,因为它们存储结果:

    csharp 复制代码
    var highestScore = (
        from score in scores
        select score
    ).Max();
    
    // 或者拆分表达式
    IEnumerable<int> scoreQuery = // 查询变量
        from score in scores
        select score;
    
    var highScore = scoreQuery.Max(); // 存储查询结果的变量
    // 如下返回同样的结果
    highScore = scores.Max();
    csharp 复制代码
    var largeCitiesList = (
        from country in countries
        from city in country.Cities
        where city.Population > 10000
        select city
    ).ToList();
    
    // 或者拆分表达式
    IEnumerable<City> largeCitiesQuery = // 查询变量
        from country in countries
        from city in country.Cities
        where city.Population > 10000
        select city;
    var largeCitiesList2 = largeCitiesQuery.ToList(); // 存储查询结果的变量

下一篇