
参考资料
💡 建议
- 内容建议完整学习;
- 内容可以根据需要学习。
- C# 中的语言集成查询 (LINQ) | Microsoft Learn
- LINQ 查询简介 - C# | Microsoft Learn
- 查询表达式基础 (LINQ) - C# | Microsoft Learn
要点
-
所有 LINQ 查询操作都由以下三个不同的操作组成:
- 获取数据源
- 创建查询
- 执行查询
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
循环的情况下对查询求值并存储其结果,只需调用查询变量上的以下方法之一: -
在存储查询结果时,应将返回的集合对象分配给一个新变量,如下面的示例所示:
csharpList<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 子句开头,且必须以 select 或 group 子句结尾 。在第一个
from
子句与最后一个select
或group
子句之间,可以包含以下这些可选子句中的一个或多个:where、orderby、join、let,甚至是其他from
子句。还可以使用 into 关键字启用join
或group
子句的结果,作为同一查询表达式中更多查询子句的源。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
变量。只要既没有修改它,也没有修改数据源,便会生成相同结果。 -
查询变量可以存储采用查询语法、方法语法或是两者的组合进行表示的查询。在以下示例中,
queryMajorCities
和queryMajorCities2
都是查询变量:csharpCity[] 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 }
-
另一方面,以下两个示例演示不是查询变量的变量(即使各自使用查询进行初始化)。它们不是查询变量,因为它们存储结果:
csharpvar highestScore = ( from score in scores select score ).Max(); // 或者拆分表达式 IEnumerable<int> scoreQuery = // 查询变量 from score in scores select score; var highScore = scoreQuery.Max(); // 存储查询结果的变量 // 如下返回同样的结果 highScore = scores.Max();
csharpvar 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(); // 存储查询结果的变量