windows C#-编写 C# LINQ 查询(上)

ops/2024/11/20 23:11:09/

介绍性的语言集成查询 (LINQ) 文档中的大多数查询是使用 LINQ 声明性查询语法编写的。 但是在编译代码时,查询语法必须转换为针对 .NET 公共语言运行时 (CLR) 的方法调用。 这些方法调用会调用标准查询运算符(名称为 Where、Select、GroupBy、Join、Max 和 Average 等)。 可以使用方法语法(而不查询语法)来直接调用它们。

查询语法和方法语法在语义上是相同的,但是查询语法通常更简单且更易于阅读。 某些查询必须表示为方法调用。 例如,必须使用方法调用表示检索与指定条件匹配的元素数的查询。 还必须对检索源序列中具有最大值的元素的查询使用方法调用。 System.Linq 命名空间中的标准查询运算符的参考文档通常使用方法语法。 你应该熟悉如何在查询和查询表达式本身中使用方法语法。

标准查询运算符扩展方法

下面的示例演示一个简单查询表达式以及编写为基于方法的查询的语义上等效的查询。

int[] numbers = [ 5, 10, 8, 3, 6, 12 ];//Query syntax:
IEnumerable<int> numQuery1 =from num in numberswhere num % 2 == 0orderby numselect num;//Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);foreach (int i in numQuery1)
{Console.Write(i + " ");
}
Console.WriteLine(System.Environment.NewLine);
foreach (int i in numQuery2)
{Console.Write(i + " ");
}

这两个示例的输出是相同的。 可以看到查询变量的类型在两种形式中是相同的:IEnumerable<T>。

为了了解基于方法的查询,我们来仔细讨论它。 在表达式右侧,请注意,where 子句现在表示为 numbers 对象上的实例方法,它具有类型 IEnumerable<int>。 如果熟悉泛型 IEnumerable<T> 接口,则会知道它没有 Where 方法。 但是,如果在 Visual Studio IDE 中调用 IntelliSense 完成列表,则不仅会看到 Where 方法,还会看到许多其他方法(如 Select、SelectMany、Join 和 Orderby)。 这些方法实现标准查询运算符。

虽然看起来好像 IEnumerable<T> 包括其他方法,但它没有。 标准查询运算符作为扩展方法来实现。 扩展方法可“扩展”现有类型;它们可以如同类型上的实例方法一样进行调用。 标准查询运算符扩展了 IEnumerable<T>,因此可以写入 numbers.Where(...)。

若要使用扩展方法,请使用 using 指令将它们引入范围。 从应用程序的角度来看,扩展方法与常规实例方法是相同的。

某些 LINQ 提供程序(如 实体框架和 LINQ to XML),会实现自己的标准查询运算符,并为 IEnumerable<T> 之外的其他类型实现扩展方法。

Lambda 表达式

在上面的示例中,请注意,条件表达式 (num % 2 == 0) 作为内联参数传递给 Enumerable.Where 方法:Where(num => num % 2 == 0). 此内联表达式为 lambda 表达式。 编写代码是一种方便的方法,否则必须以更繁琐的形式编写代码。 运算符左侧的 num 是输入变量,它与查询表达式中的 num 对应。 编译器可以推断出 num 的类型,因为它知道 numbers 是泛型 IEnumerable<T> 类型。 Lambda 的主体与查询语法中或任何其他 C# 表达式或语句中的表达式完全相同。 它可以包含方法调用和其他复杂逻辑。 返回值就是表达式结果。 某些查询只能采用方法语法进行表示,而其中一些查询需要 lambda 表达式。 Lambda 表达式是 LINQ 工具箱中的一个强大且灵活的工具。

查询的可组合性

在前面的代码示例中,Enumerable.OrderBy 方法通过对 Where 调用使用点运算符来调用。 Where 生成筛选序列,然后 Orderby 对 Where 所生成的序列进行排序。 由于查询返回 IEnumerable,因此可通过将方法调用链接在一起在方法语法中撰写查询。 使用查询语法编写查询时,编译器会执行此组合。 因为查询变量不存储查询的结果,所以可以随时修改它或将它用作新查询的基础(即使在执行它之后)。

下面的示例演示使用前面列出的每种方法的一些简单 LINQ 查询。

示例 - 查询语法

使用查询语法编写大多数查询来创建查询表达式。 下面的示例演示三个查询表达式。 第一个查询表达式演示如何通过应用包含 where 子句的条件来筛选或限制结果。 它返回源序列中值大于 7 或小于 3 的所有元素。 第二个表达式演示如何对返回的结果进行排序。 第三个表达式演示如何根据某个键对结果进行分组。 此查询基于单词的第一个字母返回两个组。

List<int> numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0];// The query variables can also be implicitly typed by using var// Query #1.
IEnumerable<int> filteringQuery =from num in numberswhere num is < 3 or > 7select num;// Query #2.
IEnumerable<int> orderingQuery =from num in numberswhere num is < 3 or > 7orderby num ascendingselect num;// Query #3.
string[] groupingQuery = ["carrots", "cabbage", "broccoli", "beans", "barley"];
IEnumerable<IGrouping<char, string>> queryFoodGroups =from item in groupingQuerygroup item by item[0];

查询的类型为 IEnumerable<T>。 可以使用 var 编写所有这些查询,如下面的示例所示:

var query = from num in numbers...

在前面的每个示例中,在 foreach 语句或其他语句中循环访问查询变量之前,查询不会实际执行。

示例 - 方法语法

某些查询操作必须表示为方法调用。 最常见的此类方法是可返回单一数值的方法,例如 Sum、Max、Min、Average 等。 这些方法在任何查询中都必须始终最后一个调用,因为它们返回单个值,不能用作额外查询操作的源。 下面的示例演示查询表达式中的方法调用:

List<int> numbers1 = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0];
List<int> numbers2 = [15, 14, 11, 13, 19, 18, 16, 17, 12, 10];// Query #4.
double average = numbers1.Average();// Query #5.
IEnumerable<int> concatenationQuery = numbers1.Concat(numbers2);

如果方法具有 System.Action 或 System.Func<TResult> 参数,则这些参数以 lambda 表达式的形式提供,如下面的示例所示:

// Query #6.
IEnumerable<int> largeNumbersQuery = numbers2.Where(c => c > 15);

在前面的查询中,只有查询 #4 立即执行,因为它返回单个值,而不是泛型 IEnumerable<T> 集合。 方法本身使用 foreach 或类似的代码来计算其值。

上面的每个查询可以通过 var 使用隐式类型化进行编写,如下面的示例所示:

// var is used for convenience in these queries
double average = numbers1.Average();
var concatenationQuery = numbers1.Concat(numbers2);
var largeNumbersQuery = numbers2.Where(c => c > 15);
示例 - 混合查询和方法语法

此示例演示如何对查询子句的结果使用方法语法。 只需将查询表达式括在括号中,然后应用点运算符并调用方法。 在下面的示例中,查询 #7 返回对值介于 3 与 7 之间的数字进行的计数。 但是通常情况下,最好使用另一个变量存储方法调用的结果。 采用此方法时,查询不太可能与查询的结果相混淆。

// Query #7.// Using a query expression with method syntax
var numCount1 = (from num in numbers1where num is > 3 and < 7select num
).Count();// Better: Create a new variable to store
// the method call result
IEnumerable<int> numbersQuery =from num in numbers1where num is > 3 and < 7select num;var numCount2 = numbersQuery.Count();

由于查询 #7 返回单个值而不是集合,因此查询立即执行。

// 前面的查询可以通过 var 使用隐式类型化进行编写,如下所示:
var numCount = (from num in numbers...// 它可以采用方法语法进行编写,如下所示:
var numCount = numbers.Count(n => n is > 3 and < 7);//它可以使用显式类型化进行编写,如下所示:
int numCount = numbers.Count(n => n is > 3 and < 7);

http://www.ppmy.cn/ops/135349.html

相关文章

Python绘制雪花

文章目录 系列目录写在前面技术需求完整代码代码分析1. 代码初始化部分分析2. 雪花绘制核心逻辑分析3. 窗口保持部分分析4. 美学与几何特点总结 写在后面 系列目录 序号直达链接爱心系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4…

199. 二叉树的右视图【 力扣(LeetCode) 】

文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 199. 二叉树的右视图 一、题目描述 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 二…

Node.js 版本管理的最终答案 Volta

文章目录 特点安装Unix系统安装Windows系统安装 常用命令volta fetchvolta installvolta uninstallvolta pinvolta listvolta completionsvolta whichvolta setupvolta runvolta help 建议 目前对于前端项目的node 版本&#xff0c;我们一般会在项目 package.json 的 engines 字…

lua调用C语言函数,在函数中进行类型检查

使用lua_is*函数族进行检查&#xff08;除了lua_type之外的另一种方式&#xff09; Lua C API提供了一系列lua_is*函数&#xff0c;如lua_isnumber、lua_isstring、lua_isboolean等&#xff0c;用于检查栈上元素的类型。示例代码如下&#xff0c;假设我们有一个C函数&#xff0…

Deep-Live-Cam -面部交换、视频深度伪造

文章目录 一、关于 Deep-Live-Cam免责声明 二、安装&#xff08;Windows/Nvidia&#xff09;安装&#xff08;手动&#xff09;基本安装&#xff08;CPU&#xff09; GPU加速&#xff08;可选&#xff09;CUDA执行提供商&#xff08;Nvidia&#xff09;CoreML执行提供商&#x…

Linux系统Centos设置开机默认root用户

目录 一. 教程 二. 部分第三方工具配置也无效 一. 教程 使用 Linux 安装Centos系统的小伙伴大概都知道&#xff0c;我们进入系统后&#xff0c;通常都是自己设置的普通用户身份&#xff0c;而不是 root 超级管理员用户&#xff0c;导致我们在操作文件夹时往往爆出没有权限&am…

Java 设计模式 详解

在Java开发中&#xff0c;设计模式是一种常见的、成熟的解决方案&#xff0c;用于应对特定的设计问题和复杂性管理。以下是一些常用的设计模式&#xff0c;它们可以分为三类&#xff1a;创建型模式、结构型模式和行为型模式。 一、创建型模式 创建型模式主要负责对象的创建&a…

Android开发实战班 - Android开发基础之 Kotlin语言基础与特性

Kotlin 是一种现代化的编程语言&#xff0c;由 JetBrains 开发&#xff0c;现已成为 Android 官方支持的开发语言。相比于 Java&#xff0c;Kotlin 提供了更简洁、安全和高效的语法特性&#xff0c;极大地提升了开发效率。本章节将深入讲解 Kotlin 的基础语法和核心特性&#x…