全部折叠 代码:C# 语言集成查询 (LINQ) 语言集成查询 (LINQ) 发送反馈意见 语言集成查询 (LINQ) 是 Visual Studio 2008 中的一组功能,可为 C# 和 Visual Basic 语言语法提供强大的查询功 能。LINQ 引入了标准的、易于学习的查询和更新数据模式,可以对其技术进行扩展以支持几乎任何类型的数据存 储。Visual Studio 2008 包含 LINQ 提供程序的程序集,这些程序集支持将 LINQ 与 .NET Framework 集合、SQL Server 数据库、ADO.NET 数据集和 XML 文档一起使用。 本节内容 相关章节 LINQ 简介 简要介绍可编写的各种应用程序,以及使用 LINQ 查询可以解决的各种问题。 C# 中的 LINQ 入门 描述为理解 C# 文档和示例所应了解的基本情况。 Visual Basic 中的 LINQ 入门 描述为理解 Visual Basic 文档和示例所应了解的基本情况。 如何:创建 LINQ 项目 介绍生成 LINQ 项目所需的 .NET Framework 版本、引用和命名空间。 对 LINQ 的 Visual Studio IDE 和工具支持 描述对象关系设计器、对查询的调试器支持以及其他与 LINQ 相关的 IDE 功能。 LINQ 常规编程指南 提供了指向相关主题的链接,这些主题包含有关如何使用 LINQ 进行编程的信息,例如标准查询运算符、表 达式目录树和查询提供程序。 LINQ to Objects 包含指向相关主题的链接,这些主题说明如何使用 LINQ to Objects 来访问内存中的数据结构。 LINQ to XML 包含指向说明如何使用 LINQ to XML 的主题的链接,此功能可提供文档对象模型 (DOM) 的内存中文档修改 功能,并且支持 LINQ 查询表达式。 LINQ to ADO.NET(门户页) 提供 linq_dataset 和 vbtecdlinq 相关文档的入口点。 LINQ to DataSet 使您可以通过使用为其他数据源提供的相同查询功能,在 DataSet 中加入更丰富的查询功能。 LINQ to SQL 为将关系数据作为对象进行管理提供了运行时基础结构。 补充的 LINQ 资源 指向 LINQ 相关信息的其他联机资源的链接。 LINQ to SQL 介绍 LINQ to SQL 技术并提供指向可帮助您使用 LINQ to SQL 的主题的链接。 LINQ to ADO.NET(门户页) 介绍 LINQ to DataSet 技术并提供指向可帮助您使用 LINQ to DataSet 的主题的链接。 LINQ 示例 提供指向相关示例的链接,这些示例用于说明 LINQ 的方方面面。 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,1/1(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/a73c4aec-5d15-4e98-... 全部折叠 代码:C# 语言集成查询 (LINQ) LINQ 简介 请参见 发送反馈意见 语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中一项突破性的创新,它在对象领域和数据 领域之间架起了一座桥梁。 传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或 IntelliSense 支持。此外,您还必须 针对以下各种数据源学习不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等。LINQ 使查询成为 C# 和 Visual Basic 中的一等语言构造。您可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。下图显示 了一个用 C# 语言编写的、不完整的 LINQ 查询,该查询针对 SQL Server 数据库,并具有完全类型检查和 IntelliSense 支持。 在 Visual Studio 中,可以用 Visual Basic 或 C# 为以下各种数据源编写 LINQ 查询:SQL Server 数据库、XML 文 档、ADO.NET 数据集以及支持 IEnumerable 或泛型 IEnumerable(T) 接口的任意对象集合。此外,还计划了对 ADO.NET Entity Framework 的 LINQ 支持,并且第三方为许多 Web 服务和其他数据库实现编写了 LINQ 提供程序。 LINQ 查询既可在新项目中使用,也可在现有项目中与非 LINQ 查询一起使用。唯一的要求是项目应面向 .NET Framework 3.5 版。 后续步骤 请参见 若要了解有关 LINQ 的更多详细信息,请先根据所选的语言熟悉“入门”部分的一些基本概念: z C# 中的 LINQ 入门 z Visual Basic 中的 LINQ 入门 然后,阅读以下文档以学习您感兴趣的 LINQ 技术: z SQL Server 数据库:LINQ to SQL z XML 文档:LINQ to XML z ADO.NET 数据集:LINQ to DataSet z .NET 集合、文件、字符串等:LINQ to Objects 概念 语言集成查询 (LINQ) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,1/1(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/24dddf19-12a0-4707-... 全部折叠 代码:C# 语言集成查询 (LINQ) C# 中的 LINQ 入门 请参见 发送反馈意见 本节包含可帮助您了解 LINQ 文档和示例的其余内容的基本背景信息。 本节内容 相关章节 请参见 LINQ 查询简介 介绍所有语言和数据源共有的基本 LINQ 查询操作的三个部分。 LINQ 和泛型类型 简单介绍泛型类型在 LINQ 中的使用。 基本查询操作 (LINQ) 介绍最常见的查询操作类型及其在 Visual Basic 和 C# 中的表示方法。 使用 LINQ 进行数据转换 介绍转换在查询中检索到的数据时可采用的各种方式。 查询操作中的类型关系 (LINQ) 介绍如何在 LINQ 查询操作的三个部分中保留和/或转换类型 查询语法与方法语法 (LINQ) 比较方法语法和查询语法这两种 LINQ 查询表示方法。 支持 LINQ 的 C# 3.0 功能 介绍 C# 3.0 中增加的支持 LINQ 的语言构造。 演练:在 C# 中编写查询 (LINQ) 关于创建 C# LINQ 项目、添加简单数据源和执行某些基本查询操作的分步说明。 语言集成查询 (LINQ) 提供指向阐述 LINQ 技术的主题的链接。 LINQ 查询表达式(C# 编程指南) 概述 LINQ 中的查询并提供指向其他资源的链接。 对 LINQ 的 Visual Studio IDE 和工具支持 介绍可在 Visual Studio 环境中用于设计、编码和调试支持 LINQ 的应用程序的工具。 如何:创建 LINQ 项目 介绍创建 LINQ 项目所需的 .NET Framework 版本、命名空间和引用。 LINQ 常规编程指南 包括指向提供特定 LINQ 功能的详细信息的主题的链接。 LINQ 示例 提供指向阐述 LINQ 示例的主题的链接。 概念 语言集成查询 (LINQ) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,1/1(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/b8700c1f-05c9-4380-... 全部折叠 代码:C# 语言集成查询 (LINQ) LINQ 查询简介 请参见 发送反馈意见 查询是一种从数据源检索数据的表达式。查询通常用专门的查询语言来表示。随着时间的推移,人们已经为各种数 据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。因此,开发人员不得不针对他们 必须支持的每种数据源或数据格式而学习新的查询语言。LINQ 通过提供一种跨各种数据源和数据格式使用数据的一 致模型,简化了这一情况。在 LINQ 查询中,始终会用到对象。可以使用相同的基本编码模式来查询和转换 XML 文 档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。 查询操作的三个部分 所有 LINQ 查询操作都由以下三个不同的操作组成: 1. 获取数据源。 2. 创建查询。 3. 执行查询。 下面的示例演示如何用源代码表示查询操作的三个部分。为了方便起见,此示例将一个整数数组用作数据源; 但其中涉及的概念同样适用于其他数据源。本主题的其余部分也会引用此示例。 下图显示了完整的查询操作。在 LINQ 中,查询的执行与查询本身截然不同;换句话说,如果只是创建查询变 量,则不会检索任何数据。 C# 复制代码 class IntroToLINQ { static void Main() { // The Three Parts of a LINQ Query: // 1. Data source. int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; // 2. Query creation. // numQuery is an IEnumerable var numQuery = from num in numbers where (num % 2) == 0 select num; // 3. Query execution. foreach (int num in numQuery) { Console.Write("{0,1} ", num); } } } 页码,1/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/37895c02-268c-41d5-... 数据源 查询 在上一个示例中,由于数据源是数组,因此它隐式支持泛型 IEnumerable(T) 接口。这一事实意味着该数据源 可以用 LINQ 进行查询。在 foreach 语句中执行查询,而 foreach 要求使用 IEnumerable 或 IEnumerable (T)。支持 IEnumerable(T) 或派生接口(如泛型 IQueryable(T))的类型称为“可查询类型”。 可查询类型不需要进行修改或特殊处理就可以用作 LINQ 数据源。如果源数据还没有作为可查询类型出现在内 存中,则 LINQ 提供程序必须以此方式表示源数据。例如,LINQ to XML 将 XML 文档加载到可查询的 XElement 类型中: 在 LINQ to SQL 中,首先手动或使用 对象关系设计器(O/R 设计器) 在设计时创建对象关系映射。针对这些 对象编写查询,然后由 LINQ to SQL 在运行时处理与数据库的通信。在下面的示例中,Customer 表示数据库 中的特定表,并且 Table 支持派生自 IEnumerable(T) 的泛型 IQueryable(T) 接口。 有关如何创建特定类型的数据源的更多信息,请参见各种 LINQ 提供程序的文档。但基本规则非常简单:LINQ 数据源是支持泛型 IEnumerable(T) 接口或从该接口继承的接口的任意对象。 C# 复制代码 // Create a data source from an XML document. // using System.Xml.Linq; XElement contacts = XElement.Load(@"c:\myContactList.xml"); C# 复制代码 // Create a data source from a SQL Server database. // using System.Data.Linq; DataContext db = new DataContext(@"c:\northwind\northwnd.mdf"); 注意: 支持非泛型 IEnumerable 接口的类型(如 ArrayList)也可用作 LINQ 数据源。有关更多信息,请参见如 何:使用 LINQ 查询 ArrayList。 查询指定要从数据源中检索的信息。查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化。 查询存储在查询变量中,并用查询表达式进行初始化。为使编写查询的工作变得更加容易,C# 引入了新的查 询语法。 上一个示例中的查询从整数数组中返回所有偶数。该查询表达式包含三个子句:from、where 和 select。 (如果您熟悉 SQL,您会注意到这些子句的顺序与 SQL 中的顺序相反。) from 子句指定数据源,where 子句应用筛选器,select 子句指定返回的元素的类型。LINQ 查询表达式(C# 编程指南)一节中详细讨论了 这些子句和其他查询子句。目前需要注意的是,在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数 据。它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。有关在幕后是如何构建查询的更多信 页码,2/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/37895c02-268c-41d5-... 查询执行 请参见 息,请参见标准查询运算符概述。 注意: 还可以使用方法语法来表示查询。有关更多信息,请参见查询语法与方法语法 (LINQ)。 延迟执行 如前所述,查询变量本身只是存储查询命令。实际的查询执行会延迟到在 foreach 语句中循环访问查询变量 时发生。此概念称为“延迟执行”,下面的示例对此进行了演示: foreach 语句也是检索查询结果的地方。例如,在上一个查询中,迭代变量 num 保存了返回的序列中的每个 值(一次保存一个值)。 由于查询变量本身从不保存查询结果,因此可以根据需要随意执行查询。例如,可以通过一个单独的应用程序 持续更新数据库。在应用程序中,可以创建一个检索最新数据的查询,并可以按某一时间间隔反复执行该查询 以便每次检索不同的结果。 强制立即执行 对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。Count、Max、Average 和 First 就属于此 类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。 另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。下面的查询返回源数组中偶数的计 数: 若要强制立即执行任意查询并缓存其结果,可以调用 ToList(TSource) 或 ToArray(TSource) 方法。 此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。但是,通过调用 ToList 或 ToArray,也可以将所有数据缓存在单个集合对象中。 C# 复制代码 // Query execution. foreach (int num in numQuery) { Console.Write("{0,1} ", num); } C# 复制代码 var evenNumQuery = from num in numbers where (num % 2) == 0 select num; int evenNumCount = evenNumQuery.Count(); C# 复制代码 List numQuery2 = (from num in numbers where (num % 2) == 0 select num).ToList(); // or like this: // numQuery3 is still an int[] var numQuery3 = (from num in numbers where (num % 2) == 0 select num).ToArray(); 概念 C# 中的 LINQ 入门 LINQ 示例 O/R 设计器概述 LINQ 查询表达式(C# 编程指南) foreach,in(C# 参考) 查询关键字(C# 参考) 页码,3/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/37895c02-268c-41d5-... 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,4/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/37895c02-268c-41d5-... 全部折叠 代码:C# 语言集成查询 (LINQ) LINQ 和泛型类型 请参见 发送反馈意见 LINQ 查询基于泛型类型,在 .NET Framework 的 2.0 版中引入了泛型类型。您无需深入了解泛型即可开始编写查 询。但是,您可能需要了解两个基本概念: 1. 当您创建泛型集合类(如 List(T))的实例时,您将“T”替换为列表将包含的对象的类型。例如,字符串列表 表示为 List,Customer 对象列表表示为 List。泛型列表是强类型的,且提供了比将 其元素存储为 Object 的集合更多的好处。如果您尝试将 Customer 添加到 List,则会在编译时出 现一条错误。泛型集合易于使用的原因是您不必执行运行时类型强制转换。 2. IEnumerable(T) 是一个接口,通过该接口,可以使用 foreach 语句来枚举泛型集合类。泛型集合类支持 IEnumerable(T),就像非泛型集合类(如 ArrayList)支持 IEnumerable。 有关泛型的更多信息,请参见泛型(C# 编程指南)。 LINQ 查询中的 IEnumerable 变量 让编译器处理泛型类型声明 请参见 LINQ 查询变量类型化为 IEnumerable(T) 或派生类型,如 IQueryable(T)。当您看到类型化为 IEnumerable 的查询变量时,这只意味着在执行该查询时,该查询将生成包含零个或多个 Customer 对象的序列。 有关更多信息,请参见查询操作中的类型关系 (LINQ)。 C# 复制代码 IEnumerable customerQuery = from cust in customers where cust.City == "London" select cust; foreach (Customer customer in customerQuery) { Console.WriteLine(customer.LastName + ", " + customer.FirstName); } 如果您愿意,可以使用 var 关键字来避免使用泛型语法。var 关键字指示编译器通过查看在 from 子句中指 定的数据源来推断查询变量的类型。下面的示例生成与上一个示例相同的编译代码: 当变量的类型明显或显式指定嵌套泛型类型(如由组查询生成的那些类型)并不重要时,var 关键字很有用。 通常,我们建议如果您使用 var,应意识到这可能使您的代码更难以让别人理解。有关更多信息,请参见隐式 类型的局部变量(C# 编程指南)。 C# 复制代码 var customerQuery2 = from cust in customers where cust.City == "London" select cust; foreach(var customer in customerQuery2) { Console.WriteLine(customer.LastName + ", " + customer.FirstName); } 概念 C# 中的 LINQ 入门 泛型(C# 编程指南) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,1/1(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/660e3799-25ca-462c-... 全部折叠 代码:C# 语言集成查询 (LINQ) 基本查询操作 (LINQ) 请参见 发送反馈意见 本主题简要介绍 LINQ 查询表达式,以及您在查询中执行的一些典型类型的操作。下面各主题中提供了更详细的信 息: LINQ 查询表达式(C# 编程指南) 标准查询运算符概述 获取数据源 筛选 排序 注意: 如果您已熟悉查询语言(如 SQL 或 XQuery),则您可以跳过本主题的大部分内容。阅读下一节中的“from 子 句”来了解 LINQ 查询表达式中的子句的顺序。 在 LINQ 查询中,第一步是指定数据源。像在大多数编程语言中一样,在 C# 中,必须先声明变量,才能使用 它。在 LINQ 查询中,最先使用 from 子句的目的是引入数据源 (customers) 和范围变量 (cust)。 范围变量类似于 foreach 循环中的迭代变量,但在查询表达式中,实际上不发生迭代。执行查询时,范围变 量将用作对 customers 中的每个后续元素的引用。因为编译器可以推断 cust 的类型,所以您不必显式指定 此类型。其他范围变量可由 let 子句引入。有关更多信息,请参见 let 子句(C# 参考)。 C# 复制代码 //queryAllCustomers is an IEnumerable var queryAllCustomers = from cust in customers select cust; 注意: 对于非泛型数据源(如 ArrayList),必须显式类型化范围变量。有关更多信息,请参见如何:使用 LINQ 查询 ArrayList和 from 子句(C# 参考)。 也许最常用的查询操作是应用布尔表达式形式的筛选器。此筛选器使查询只返回那些表达式结果为 true 的元 素。使用 where 子句生成结果。实际上,筛选器指定从源序列中排除哪些元素。在下面的示例中,只返回那 些地址位于伦敦的 customers。 您可以使用熟悉的 C# 逻辑 AND 和 OR 运算符来根据需要在 where 子句中应用任意数量的筛选表达式。例 如,若要只返回位于“伦敦”AND 姓名为“Devon”的客户,您应编写下面的代码: 若要返回位于伦敦或巴黎的客户,您应编写下面的代码: 有关更多信息,请参见 where 子句(C# 参考)。 C# 复制代码 var queryLondonCustomers = from cust in customers where cust.City == "London" select cust; C# 复制代码 where cust.City=="London" && cust.Name == "Devon" C# 复制代码 where cust.City == "London" || cust.City == "Paris" 通常可以很方便地将返回的数据进行排序。orderby 子句将使返回的序列中的元素按照被排序的类型的默认比 较器进行排序。例如,下面的查询可以扩展为按 Name 属性对结果进行排序。因为 Name 是一个字符串,所以 默认比较器执行从 A 到 Z 的字母排序。 C# 页码,1/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/a7ea3421-1cf4-4df7-8... 分组 联接 选择(投影) 若要按相反顺序(从 Z 到 A)对结果进行排序,请使用 orderby…descending 子句。 有关更多信息,请参见 orderby 子句(C# 参考)。 复制代码 var queryLondonCustomers3 = from cust in customers where cust.City == "London" orderby cust.Name ascending select cust; 使用 group 子句,您可以按指定的键分组结果。例如,您可以指定结果应按 City 分组,以便位于伦敦或巴 黎的所有客户位于各自组中。在本例中,cust.City 是键。 在使用 group 子句结束查询时,结果采用列表的列表形式。列表中的每个元素是一个具有 Key 成员及根据该 键分组的元素列表的对象。在循环访问生成组序列的查询时,您必须使用嵌套的 foreach 循环。外部循环用 于循环访问每个组,内部循环用于循环访问每个组的成员。 如果您必须引用组操作的结果,可以使用 into 关键字来创建可进一步查询的标识符。下面的查询只返回那些 包含两个以上的客户的组: 有关更多信息,请参见 group 子句(C# 参考)。 注意: 在下面的示例中,类型是显式的以更好地说明概念。您也可以对 custQuery、group 和 customer 使用隐 式类型以让编译器确定准确的类型。 C# 复制代码 // queryCustomersByCity is an IEnumerable> var queryCustomersByCity = from cust in customers group cust by cust.City; // customerGroup is an IGrouping foreach (var customerGroup in queryCustomersByCity) { Console.WriteLine(customerGroup.Key); foreach (Customer customer in customerGroup) { Console.WriteLine(" {0}", customer.Name); } } C# 复制代码 // custQuery is an IEnumerable> var custQuery = from cust in customers group cust by cust.City into custGroup where custGroup.Count() > 2 orderby custGroup.Key select custGroup; 联接运算创建数据源中没有显式建模的序列之间的关联。例如,您可以执行联接来查找符合以下条件的所有客 户:位于巴黎,且从位于伦敦的供应商处订购产品。在 LINQ 中,join 子句始终针对对象集合而非直接针对数 据库表运行。在 LINQ 中,您不必像在 SQL 中那样频繁使用 join,因为 LINQ 中的外键在对象模型中表示为 包含项集合的属性。例如,Customer 对象包含 Order 对象的集合。不必执行联接,只需使用点表示法访问订 单: 有关更多信息,请参见 join 子句(C# 参考)。 复制代码 from order in Customer.Orders... 页码,2/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/a7ea3421-1cf4-4df7-8... 请参见 select 子句生成查询结果并指定每个返回的元素的“形状”或类型。例如,您可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。当 select 子句生成除源元素副本以外的内容时,该操作称为“投影”。使用投影转换数据是 LINQ 查询表达式的 一种强大功能。有关更多信息,请参见使用 LINQ 进行数据转换和 select 子句(C# 参考)。 概念 C# 中的 LINQ 入门 LINQ 查询表达式(C# 编程指南) 查询关键字(C# 参考) 匿名类型(C# 编程指南) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,3/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/a7ea3421-1cf4-4df7-8... 全部折叠 代码:C# 语言集成查询 (LINQ) 使用 LINQ 进行数据转换 请参见 发送反馈意见 语言集成查询 (LINQ) 不仅可用于检索数据,而是还是一个功能强大的数据转换工具。通过使用 LINQ 查询,您可以将源序列用作输入,并采 用多种方式修改它以创建新输出序列。您可以通过排序和分组来修改序列本身,而不必修改元素本身。但是,LINQ 查询最强大的功能可能在 于它能够创建新类型。这一功能在 select 子句中实现。例如,可以执行下列任务: z 将多个输入序列合并到具有新类型的单个输出序列中。 z 创建其元素只包含源序列中的各个元素的一个或几个属性的输出序列。 z 创建其元素包含对源数据执行的操作结果的输出序列。 z 创建不同格式的输出序列。例如,您可以将 SQL 行或文本文件的数据转换为 XML。 这只是几个示例。当然,可以采用多种方式将这些转换组合在同一查询中。另外,一个查询的输出序列可用作新查询的输入序列。 将多个输入联接到一个输出序列 可以使用 LINQ 查询来创建包含多个输入序列的元素的输出序列。下面的示例演示如何组合两个内存中的数据结构,但组合来自 XML 或 SQL 或数据集源的数据时可应用相同的原则。假定下面两种类类型: 下面的示例演示该查询: C# 复制代码 class Student { public string First { get; set; } public string Last {get; set;} public int ID { get; set; } public string Street { get; set; } public string City { get; set; } public List Scores; } class Teacher { public string First { get; set; } public string Last { get; set; } public int ID { get; set; } public string City { get; set; } } C# 复制代码 class DataTransformations { static void Main() { // Create the first data source. List students = new List() { new Student {First="Svetlana", Last="Omelchenko", ID=111, Street="123 Main Street", City="Seattle", Scores= new List {97, 92, 81, 60}}, new Student {First="Claire", Last="O’Donnell", ID=112, Street="124 Main Street", City="Redmond", Scores= new List {75, 84, 91, 39}}, new Student {First="Sven", Last="Mortensen", ID=113, Street="125 Main Street", City="Lake City", Scores= new List {88, 94, 65, 91}}, }; // Create the second data source. List teachers = new List() { new Teacher {First="Ann", Last="Beebe", ID=945, City = "Seattle"}, new Teacher {First="Alex", Last="Robinson", ID=956, City = "Redmond"}, new Teacher {First="Michiyo", Last="Sato", ID=972, City = "Tacoma"} }; // Create the query. var peopleInSeattle = (from student in students where student.City == "Seattle" select student.Last) .Concat(from teacher in teachers where teacher.City == "Seattle" select teacher.Last); Console.WriteLine("The following students and teachers live in Seattle:"); // Execute the query. foreach (var person in peopleInSeattle) { Console.WriteLine(person); 页码,1/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/674eae9e-bc72-4a88-... 选择各个源元素的子集 将内存中的对象转换为 XML 有关更多信息,请参见 join 子句(C# 参考)和 select 子句(C# 参考)。 } Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Output: The following students and teachers live in Seattle: Omelchenko Beebe */ 选择源序列中的各个元素的子集有两种主要方法: 1. 若要只选择源元素的一个成员,请使用点运算。在下面的示例中,假定 Customer 对象包含几个公共属性,其中包括名为 City 的字符串。在执行此查询时,此查询将生成字符串输出序列。 2. 若要创建包含源元素的多个属性的元素,可以使用具有命名对象或匿名类型的对象初始值设定项。下面的示例演示如何使用匿名 类型来封装各个 Customer 元素的两个属性: 有关更多信息,请参见对象和集合初始值设定项(C# 编程指南)和匿名类型(C# 编程指南)。 复制代码 var query = from cust in Customers select cust.City; 复制代码 var query = from cust in Customer select new {Name = cust.Name, City = cust.City}; 通过 LINQ 查询,可以轻松地在内存中的数据结构、SQL 数据库、ADO.NET 数据集和 XML 流或文档之间转换数据。下面的示例将内存 中的数据结构中的对象转换为 XML 元素。 此代码生成下面的 XML 输出: C# 复制代码 class XMLTransform { static void Main() { // Create the data source by using a collection initializer. List students = new List() { new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List{97, 92, 81, 60}}, new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List{75, 84, 91, 39}}, new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List{88, 94, 65, 91}}, }; // Create the query. var studentsToXML = new XElement("Root", from student in students let x = String.Format("{0},{1},{2},{3}", student.Scores[0], student.Scores[1], student.Scores[2], student.Scores[3]) select new XElement("student", new XElement("First", student.First), new XElement("Last", student.Last), new XElement("Scores", x) ) // end "student" ); // end "Root" // Execute the query. Console.WriteLine(studentsToXML); // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } 复制代码 < Root> Svetlana Omelchenko 97,92,81,60 Claire O'Donnell 75,84,91,39 Sven Mortensen 88,94,65,91 页码,2/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/674eae9e-bc72-4a88-... 对源元素执行操作 请参见 有关更多信息,请参见使用 C# 创建 XML 树 (LINQ to XML)。 输出序列可能不包含源序列的任何元素或元素属性。输出可能是通过将源元素用作输入参数计算出的值的序列。在执行下面这个简单查 询时,此查询会输出一个字符串序列,该序列值表示根据 double 类型的元素的源序列进行的计算。 注意: 如果查询将转换为某个其他域,则不支持在查询表达式中调用方法。例如,不能在 LINQ to SQL 中调用一般 C# 方法,因为 SQL Server 没有该方法的上下文。但是,可以将存储过程映射到方法,然后调用方法。有关更多信息,请参见存储过程 (LINQ to SQL)。 C# 复制代码 class FormatQuery { static void Main() { // Data source. double[] radii = { 1, 2, 3 }; // Query. IEnumerable query = from rad in radii select String.Format("Area = {0}", (rad * rad) * 3.14); // Query execution. foreach (string s in query) Console.WriteLine(s); // Keep the console open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); } } /* Output: Area = 3.14 Area = 12.56 Area = 28.26 */ 概念 语言集成查询 (LINQ) LINQ to SQL LINQ to DataSet LINQ to XML LINQ 查询表达式(C# 编程指南) select 子句(C# 参考) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,3/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/674eae9e-bc72-4a88-... 全部折叠 代码:C# 语言集成查询 (LINQ) 查询操作中的类型关系 (LINQ) 请参见 发送反馈意见 若要有效编写查询,您应该了解完整的查询操作中的变量类型是如何全部彼此关联的。如果您了解这些关系,就能 够更容易地理解文档中的 LINQ 示例和代码示例。另外,还能了解在使用 var 隐式对变量进行类型化时的后台操 作。 LINQ 查询操作在数据源、查询本身及查询执行中是强类型的。查询中变量的类型必须与数据源中元素的类型和 foreach 语句中迭代变量的类型兼容。此强类型保证在编译时捕获类型错误,以便可以在用户遇到这些错误之前更 正它们。 为了演示这些类型关系,下面的大多数示例对所有变量使用显式类型。最后一个示例演示在您利用使用 var 的隐式 类型时,如何应用相同的原则。 不转换源数据的查询 转换源数据的查询 下图演示不对数据执行转换的 LINQ to Objects 查询操作。源包含一个字符串序列,查询输出也是一个字符串 序列。 1. 数据源的类型参数决定范围变量的类型。 2. 选择的对象的类型决定查询变量的类型。此处的 name 为一个字符串。因此,查询变量是一个 IEnumerable。 3. 在 foreach 语句中循环访问查询变量。因为查询变量是一个字符串序列,所以迭代变量也是一个字符 串。 下图演示对数据执行简单转换的 LINQ to SQL 查询操作。查询将一个 Customer 对象序列用作输入,并只选 择结果中的 Name 属性。因为 Name 是一个字符串,所以查询生成一个字符串序列作为输出。 1. 数据源的类型参数决定范围变量的类型。 2. select 语句返回 Name 属性,而非完整的 Customer 对象。因为 Name 是一个字符串,所以 custNameQuery 的类型参数是 string,而非 Customer。 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/99118938-d47c-4d7e-... 让编译器推断类型信息 请参见 3. 因为 custNameQuery 是一个字符串序列,所以 foreach 循环的迭代变量也必须是 string。 下图演示稍微复杂的转换。select 语句返回只捕获原始 Customer 对象的两个成员的匿名类型。 1. 数据源的类型参数始终为查询中的范围变量的类型。 2. 因为 select 语句生成匿名类型,所以必须使用 var 隐式类型化查询变量。 3. 因为查询变量的类型是隐式的,所以 foreach 循环中的迭代变量也必须是隐式的。 虽然您应该了解查询操作中的类型关系,但是您也可以选择让编译器为您执行全部工作。关键字 var 可用于 查询操作中的任何局部变量。下图与前面讨论的第二个示例完全等效。唯一的区别是编译器将为查询操作中的 各个变量提供强类型: 有关 var 的更多信息,请参见隐式类型的局部变量(C# 编程指南)。 概念 C# 中的 LINQ 入门 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/99118938-d47c-4d7e-... 全部折叠 代码:C# 语言集成查询 (LINQ) 查询语法与方法语法 (LINQ) 请参见 发送反馈意见 通过使用 C# 3.0 中引入的声明性查询语法,介绍性 LINQ 文档中的多数查询都被编写为查询表达式。但是,.NET 公共语言运行库 (CLR) 本身并不具有查询语法的概念。因此,在编译时,查询表达式会转换为 CLR 确实了解的内 容:方法调用。这些方法称为“标准查询运算符”,它们具有如下名称:Where、Select、GroupBy、Join、 Max、Average 等。可以通过使用方法语法而非查询语法直接调用这些方法。 通常我们建议使用查询语法,因为它通常更简单、更易读;但是方法语法和查询语法之间并无语义上的区别。此 外,一些查询(如检索匹配指定条件的元素数的那些查询或检索具有源序列中的最大值的元素的查询)只能表示为 方法调用。System.Linq 命名空间中的标准查询运算符的参考文档通常使用方法语法。因此,即使在开始编写 LINQ 查询时,熟悉如何在查询和查询表达式本身中使用方法语法也非常有用。 标准查询运算符扩展方法 下面的示例演示简单的查询表达式和编写为基于方法的查询的语义上等效的查询。 两个示例的输出是相同的。您可以看到两种形式的查询变量的类型是相同的:IEnumerable(T)。 若要了解基于方法的查询,让我们进一步地分析它。注意,在表达式的右侧,where 子句现在表示为对 numbers 对象的实例方法,在您重新调用该对象时其类型为 IEnumerable。如果您熟悉泛型 IEnumerable(T) 接口,那么您就会了解,它不具有 Where 方法。但是,如果您在 Visual Studio IDE 中调用 IntelliSense 完成列表,那么您不仅将看到 Where 方法,而且还会看到许多其他方法,如 Select、 SelectMany、Join 和 Orderby。下面是所有标准查询运算符。 C# 复制代码 class QueryVMethodSyntax { static void Main() { int[] numbers = { 5, 10, 8, 3, 6, 12}; //Query syntax: IEnumerable numQuery1 = from num in numbers where num % 2 == 0 orderby num select num; //Method syntax: IEnumerable 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 + " "); } // Keep the console open in debug mode. Console.WriteLine(System.Environment.NewLine); Console.WriteLine("Press any key to exit"); Console.ReadKey(); } } /* Output: 6 8 10 12 6 8 10 12 */ 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/eedd6dd9-fec2-428c-9... Lambda 表达式 查询的组合性 请参见 尽管看起来 IEnumerable(T) 似乎已被重新定义以包括这些附加方法,但事实上并非如此。这些标准查询运算 符作为一种新的方法(称为“扩展方法”)实现。扩展方法可“扩展”现有类型;可如对类型的实例方法一样 调用。标准查询运算符可扩展 IEnumerable(T),这就是您可以编写 numbers.Where(...) 的原因。 若要开始使用 LINQ,您实际需要了解的有关扩展方法的所有内容是,如何通过使用正确的 using 指令将它们 置于您的应用程序中的范围内。您可以在如何:创建 LINQ 项目中进一步了解相关信息。从应用程序的角度来 看,扩展方法和正常的实例方法是相同的。 有关扩展方法的更多信息,请参见扩展方法(C# 编程指南)。有关标准查询运算符的更多信息,请参见 LINQ 常规编程指南和标准查询运算符概述 一些 LINQ 提供程序(如 LINQ to SQL 和 LINQ to XML)除了 IEnumerable(T) 外,还为其他类型实现其自身的标准查询运算符和其他扩展方法。 请注意,在上面的示例中,条件表达式 (num % 2 == 0) 是作为内联参数传递到 Where 方法的:Where(num => num % 2 == 0)。此内联表达式称为 lambda 表达式。将代码编写为匿名方法或泛型委托或表达式目录树 是一种便捷的方法,否则编写起来就要麻烦得多。在 C# 中,=> 是 lambda 运算符,可读为“goes to”。运 算符左侧的 num 是输入变量,与查询表达式中的 num 相对应。编译器可推断 num 的类型,因为它了解 numbers 是泛型 IEnumerable(T) 类型。lambda 表达式与查询语法中的表达式或任何其他 C# 表达式或语句 中的表达式相同;它可以包括方法调用和其他复杂逻辑。“返回值”就是表达式结果。 若要开始使用 LINQ,您不必大量使用 lambda。但是,特定查询只可使用方法语法表示,其中一些查询需要 使用 lambda 表达式。进一步熟悉 lambda 后,您会发现,在 LINQ 工具栏中,它们是强大且灵活的工具。有 关更多信息,请参见 Lambda 表达式(C# 编程指南)。 在上面的代码示例中,OrderBy 方法并非是在对 Where 的调用时使用点运算符调用的。Where 可生成筛选 序列,然后 Orderby 通过对其排序来对该序列进行运算。因为查询会返回 IEnumerable,所以您可通过将 方法调用链接在一起,在方法语法中将这些查询组合起来。这就是在您通过使用查询语法编写查询时编译器在 后台所执行的操作。并且由于查询变量不存储查询的结果,因此您可以随时修改它或将它用作新查询的基础, 即使在执行它后。 概念 C# 中的 LINQ 入门 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/eedd6dd9-fec2-428c-9... 全部折叠 代码:C# 语言集成查询 (LINQ) 支持 LINQ 的 C# 3.0 功能 请参见 发送反馈意见 下面一节介绍 C# 3.0 中的新语言构造。虽然这些新功能在一定程度上都用于 LINQ 查询,但并限于 LINQ,如果认 为有用,在任何情况下都可以使用这些新功能。 查询表达式 隐式类型化变量 (var) 对象和集合初始值设定项 匿名类型 扩展方法 查询表达式使用类似于 SQL 或 XQuery 的声明性语法来查询 IEnumerable 集合。在编译时,查询语法转换为 对 LINQ 提供程序的标准查询运算符扩展方法实现的方法调用。应用程序通过使用 using 指令指定适当的命 名空间来控制范围内的标准查询运算符。下面的查询表达式获取一个字符串数组,按字符串中的第一个字符对 字符串进行分组,然后对各组进行排序。 有关更多信息,请参见 LINQ 查询表达式(C# 编程指南)。 复制代码 var query = from str in stringArray group str by str[0] into stringGroup orderby stringGroup.Key select stringGroup; 不必在声明并初始化变量时显式指定类型,您可以使用 var 修饰符来指示编译器推断并分配类型,如下所 示: 声明为 var 的变量与显式指定其类型的变量一样都是强类型。通过使用 var,可以创建匿名类型,但它可用 于任何局部变量。也可以使用隐式类型声明数组。 有关更多信息,请参见隐式类型的局部变量(C# 编程指南)。 复制代码 var number = 5; var name = "Virginia"; var query = from str in stringArray where str[0] == 'm' select str; 通过对象和集合初始值设定项,初始化对象时无需为对象显式调用构造函数。初始值设定项通常用在将源数据 投影到新数据类型的查询表达式中。假定一个类名为 Customer,具有公共 Name 和 Phone 属性,可以按下 列代码中所示使用对象初始值设定项: 有关更多信息,请参见对象和集合初始值设定项(C# 编程指南)。 复制代码 Customer cust = new Customer {Name = "Mike" ; Phone ={ "555-1212 "}; 匿名类型由编译器构建,且类型名称只可用于编译器。匿名类型提供了一种在查询结果中临时分组一组属性的 方便方法,无需定义单独的命名类型。使用新的表达式和对象初始值设定项初始化匿名类型,如下所示: 有关更多信息,请参见匿名类型(C# 编程指南)。 复制代码 select new {name = cust.Name, phone = cust.Phone}; 扩展方法是一种可与类型关联的静态方法,因此可以像实例方法那样对类型调用它。实际上,此功能使您能够 将新方法“添加”到现有类型,而不会实际修改它们。标准查询运算符是一组扩展方法,它们为实现 IEnumerable(T) 的任何类型提供 LINQ 查询功能。 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/524b0078-ebfd-45a7-... Lambda 表达式 自动实现的属性 请参见 有关更多信息,请参见扩展方法(C# 编程指南)。 Lambda 表达式是一种内联函数,该函数使用 => 运算符将输入参数与函数体分离,并且可以在编译时转换为 委托或表达式目录树。在 LINQ 编程中,在您对标准查询运算符进行直接方法调用时,会遇到 lambda 表达 式。 有关更多信息,请参见: z 匿名函数(C# 编程指南) z Lambda 表达式(C# 编程指南) z 表达式目录树 通过自动实现的属性,可以更简明地声明属性。当您如下面的示例中所示声明属性时,编译器将创建一个私有 的匿名支持字段,该字段只能通过属性 getter 和 setter 进行访问。 有关更多信息,请参见自动实现的属性(C# 编程指南)。 复制代码 public string Name {get; set;} 概念 语言集成查询 (LINQ) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/524b0078-ebfd-45a7-... 全部折叠 代码:C# 语言集成查询 (LINQ) 演练:在 C# 中编写查询 (LINQ) 请参见 发送反馈意见 本演练将引导您学习新的 C# 3.0 语言功能,并演示如何使用这些功能来编写 LINQ 查询表达式。完成本演练后,您便可以继续学习您感 兴趣的具体 LINQ 提供程序(如 LINQ to SQL、LINQ to DataSet 或 LINQ to XML)的示例和文档。 先决条件 创建 C# 项目 创建内存中数据源 创建查询 本演练需要 Visual Studio 2008。 有关视频演示,请参见 Video How to: Writing Queries in C# (LINQ)(视频帮助:使用 C# 编写查询 (LINQ))。 创建面向 .NET Framework 3.5 版的 C# 项目 1. 启动 Visual Studio。 2. 在“文件”菜单上指向“新建”,然后单击“项目”。 3. 在“新建项目”对话框的右上角有三个图标。单击左边的图标并确保选中“.NET Framework 3.5 版”。 4. 单击“Visual Studio 已安装的模板”下面的“控制台应用程序”图标。 5. 为您的应用程序输入新的名称或接受默认名称,然后单击“确定”。 6. 请注意,您的项目具有对 System.Core.dll 的引用以及适用于 System.Linq 命名空间的 using 指令。 查询的数据源是 Student 对象的简单列表。每个 Student 记录都有名、姓和表示他们在班级中的测验分数的整数数组。将此代码 复制到您的项目中。请注意下列特性: z Student 类包含自动实现的属性。 z 列表中的每个学生都已使用对象初始值设定项进行初始化。 z 列表本身已使用集合初始值设定项进行初始化。 将在不显式调用任何构造函数和使用显式成员访问的情况下初始化并实例化整个数据结构。有关这些新功能的更多信息,请参见自 动实现的属性(C# 编程指南)和对象和集合初始值设定项(C# 编程指南)。 添加数据源 z 将 Student 类和经过初始化的学生列表添加到您的项目的 Program 类中。 在学生列表中添加新学生 z 将新 Student 添加到 Students 列表中并使用您选择的姓名和测验分数。尝试键入新学生的所有信息,以便更好地了解对象 初始值设定项的语法。 C# 复制代码 public class Student { public string First { get; set; } public string Last { get; set; } public int ID { get; set; } public List Scores; } // Create a data source by using a collection initializer. static List students = new List { new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List {97, 92, 81, 60}}, new Student {First="Claire", Last="O’Donnell", ID=112, Scores= new List {75, 84, 91, 39}}, new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List {88, 94, 65, 91}}, new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List {97, 89, 85, 82}}, new Student {First="Debra", Last="Garcia", ID=115, Scores= new List {35, 72, 91, 70}}, new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List {99, 86, 90, 94}}, new Student {First="Hanying", Last="Feng", ID=117, Scores= new List {93, 92, 80, 87}}, new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List {92, 90, 83, 78}}, new Student {First="Lance", Last="Tucker", ID=119, Scores= new List {68, 79, 88, 92}}, new Student {First="Terry", Last="Adams", ID=120, Scores= new List {99, 82, 81, 79}}, new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List {96, 85, 91, 60}}, new Student {First="Michael", Last="Tucker", ID=122, Scores= new List {94, 92, 91, 91} } }; 创建简单查询 z 在应用程序的 Main 方法中创建一个简单查询,执行该查询时,将生成第一次测验中分数高于 90 分的所有学生的列表。请注 意,由于选择了整个 Student 对象,因此查询的类型是 IEnumerable。虽然代码也可以通过使用 var 关键字来使 用隐式类型,但这里使用了显式类型以便清楚地演示结果。(有关 var 的更多信息,请参见隐式类型的局部变量(C# 编程指 南)。) 另请注意,该查询的范围变量 student 用作对源中每个 Student 的引用,以提供对每个对象的成员访问。 页码,1/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/2962a610-419a-4276-... 执行查询 修改查询 C# 复制代码 // Create the query. // studentQuery is an IEnumerable var studentQuery = from student in students where student.Scores[0] > 90 select student; 执行查询 1. 现在编写用于执行查询的 foreach 循环。请注意有关代码的以下事项: z 所返回序列中的每个元素是通过 foreach 循环中的迭代变量来访问的。 z 此变量的类型是 Student,查询变量的类型是兼容的 IEnumerable。 2. 添加此代码后,按 Ctrl + F5 生成并运行该应用程序,然后在“控制台”窗口中查看结果。 添加另一个筛选条件 z 您可以在 where 子句中组合多个布尔条件,以便进一步细化查询。下面的代码添加一个条件,以便查询返回第一个分数高于 90 分并且最后一个分数低于 80 分的那些学生。where 子句应类似于以下代码。 有关更多信息,请参见 where 子句(C# 参考)。 C# 复制代码 // Execute the query. // var could be used here also. foreach (Student student in studentQuery) { Console.WriteLine("{0}, {1}", student.Last, student.First); } 复制代码 where student.Scores[0] > 90 && student.Scores[3] < 80 对结果进行排序 1. 如果结果按某种顺序排列,则浏览结果会更容易。您可以根据源元素中的任何可访问字段对返回的序列进行排序。例如,下 面的 orderby 子句根据每个学生的姓按从 A 到 Z 的字母顺序对结果进行排序。紧靠在 where 语句之后、select 语句之 前,将下面的 orderby 子句添加到您的查询中: 2. 现在更改 orderby 子句,以便根据第一次测验的分数的反向顺序,即从高分到低分的顺序对结果进行排序。 3. 更改 WriteLine 格式字符串以便您可以查看分数: 有关更多信息,请参见 orderby 子句(C# 参考)。 对结果进行分组 1. 分组是查询表达式中的强大功能。包含 group 子句的查询将生成一系列组,每个组本身包含一个 Key 和一个序列,该序列 由该组的所有成员组成。下面的新查询使用学生的姓的第一个字母作为关键字对学生进行分组。 2. 请注意,查询的类型现在已更改。该查询现在生成一系列将 char 类型作为关键字的组,以及一系列 Student 对象。由于 查询的类型已更改,因此下面的代码也会更改 foreach 执行循环: 复制代码 orderby student.Last ascending 复制代码 orderby student.Scores[0] descending 复制代码 Console.WriteLine("{0}, {1} {2}", s.Last, s.First, s.Scores[0]); C# 复制代码 // studentQuery2 is an IEnumerable> var studentQuery2 = from student in students group student by student.Last[0]; C# 复制代码 // studentGroup is a IGrouping foreach (var studentGroup in studentQuery2) { Console.WriteLine(studentGroup.Key); foreach (Student student in studentGroup) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } 页码,2/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/2962a610-419a-4276-... 3. 按 Ctrl + F5 运行该应用程序并在“控制台”窗口中查看结果。 有关更多信息,请参见 group 子句(C# 参考)。 隐式类型化变量 z 显式编写 IGroupings 的 IEnumerables 代码很快就会变得乏味。通过使用 var,您可以更方便地编写相同的查询和 foreach 循环。var 关键字不会更改对象的类型,它仅指示编译器推断类型。将 studentQuery 和迭代变量 group 的类型更 改为 var 并重新运行查询。请注意,在内部 foreach 循环中,迭代变量仍然类型化为 Student,而查询仍可像以前一样工 作。将 s 迭代变量更改为 var 并再次运行查询。您将看到完全相同的结果。 有关 var 的更多信息,请参见隐式类型的局部变量(C# 编程指南)。 按键值对组进行排序 z 当您运行前面的查询时,会注意到组没有按字母顺序排列。若要改变这种情况,您必须在 group 子句后提供 orderby 子句。 但要使用 orderby 子句,您首先需要一个标识符,用作对 group 子句创建的组的引用。可以使用 into 关键字来提供此标识 符,如下所示: 当您运行此查询时,就会看到组现在已按字母顺序排序。 使用 let 引入标识符 z 您可以使用 let 关键字为查询表达式中的任何表达式结果引入标识符。此标识符可以提供方便(如下面的示例所示),也可以 通过存储表达式的结果来避免多次计算,从而提高性能。 有关更多信息,请参见 let 子句(C# 参考)。 在查询表达式中使用方法语法 z 如查询语法与方法语法 (LINQ) 中所述,一些查询操作只能使用方法语法表示。下面的代码计算源序列中每个 Student 的总 分,然后对该查询的结果调用 Average() 方法来计算班级的平均分。请注意,查询表达式的两边使用了括号。 C# 复制代码 var studentQuery3 = from student in students group student by student.Last[0]; foreach (var groupOfStudents in studentQuery3) { Console.WriteLine(groupOfStudents.Key); foreach (var student in groupOfStudents) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } C# 复制代码 var studentQuery4 = from student in students group student by student.Last[0] into studentGroup orderby studentGroup.Key select studentGroup; foreach (var groupOfStudents in studentQuery4) { Console.WriteLine(groupOfStudents.Key); foreach (var student in groupOfStudents) { Console.WriteLine(" {0}, {1}", student.Last, student.First); } } C# 复制代码 // studentQuery5 is an IEnumerable // This query returns those students whose // first test score was higher than their // average score. var studentQuery5 = from student in students let totalScore = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] where totalScore / 4 < student.Scores[0] select student.Last + " " + student.First; foreach (string s in studentQuery5) { Console.WriteLine(s); } C# 复制代码 var studentQuery6 = from student in students let totalScore = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] select totalScore; 页码,3/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/2962a610-419a-4276-... 后续步骤 请参见 在 select 子句中转换或投影 1. 查询生成的序列的元素与源序列中的元素不同,这种情况很常见。删除或注释掉您之前的查询和执行循环,并用下面的代码 替换它。请注意,该查询返回一个字符串(而非 Students)序列,这种情况将反映在 foreach 循环中。 2. 本演练前面的代码指出班级的平均分约为 334 分。若要生成总分高于班级平均分的 Students 及其 Student ID 的序列, 可以在 select 语句中使用匿名类型: double averageScore = studentQuery6.Average(); Console.WriteLine("Class average score = {0}", averageScore); C# 复制代码 IEnumerable studentQuery7 = from student in students where student.Last == "Garcia" select student.First; Console.WriteLine("The Garcias in the class are:"); foreach (string s in studentQuery7) { Console.WriteLine(s); } C# 复制代码 var studentQuery8 = from student in students let x = student.Scores[0] + student.Scores[1] + student.Scores[2] + student.Scores[3] where x > averageScore select new { id = student.ID, score = x }; foreach (var item in studentQuery8) { Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score); } 熟悉了在 C# 中使用查询的基本情况后,便可以开始阅读您感兴趣的具体类型的 LINQ 提供程序的文档和示例: LINQ to SQL LINQ to DataSet LINQ to XML LINQ to Objects LINQ C# 示例 概念 语言集成查询 (LINQ) C# 中的 LINQ 入门 LINQ 查询表达式(C# 编程指南) 补充的 LINQ 资源 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,4/4(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/2962a610-419a-4276-... 全部折叠 代码:C# 语言集成查询 (LINQ) 如何:创建 LINQ 项目 请参见 发送反馈意见 面向 .NET Framework 3.5 版 的新 Visual C# 和 Visual Basic 项目包括基本 LINQ 功能所需的命名空间和引用。只 需创建一个新项目,即可开始编写针对对象集合的 LINQ 查询。Visual Basic 还为 LINQ to XML 功能提供了引用和导 入的命名空间。在 Visual C# 中,必须手动添加这些内容。 若要在任一语言中使用 LINQ to XML 或 LINQ to DataSet,必须手动添加命名空间和引用,如下节所述。 如果要升级用 Visual Studio 早期版本创建的项目,则可能必须手动提供这些内容或其他与 LINQ 相关的引用,还必 须手动将此项目设置为面向 .NET Framework 3.5 版。 添加 LINQ 命名空间和引用的过程 注意: 如果在命令提示符下生成,则必须手动引用驱动器:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5 中与 LINQ 相关的 DLL。 面向 .NET Framework 3.5 版 1. 在 Visual Studio 中,打开一个在 Visual Studio 2005 中创建的 Visual Basic 或 C# 项目,然后按照提 示将它转换为 Visual Studio 2008 项目。 2. 对于 C# 项目,单击“项目”菜单,然后单击“属性”。 a. 在“应用程序”属性页中,选择“目标 Framework”下拉列表中的“.NET Framework 3.5”。 3. 对于 Visual Basic 项目,单击“项目”菜单,然后单击“属性”。 在“编译”属性页中,单击“高级编译选项”,然后在“目标 Framework(所有配置)”下拉列表中选择 “.NET Framework 3.5”。 启用基本 LINQ 功能 1. 在 Visual Basic 或 C# 项目中,单击“项目”菜单,然后单击“添加引用”。 2. 在“添加引用”对话框中单击“.NET”选项卡,滚动到 System.Core.dll 程序集,然后单击它。单击“确 定”。 3. 将 System.Linq 的 using 指令或 Imports 语句添加到您的源代码文件或项目。 有关更多信息,请参见 using 指令(C# 参考)或如何:添加或移除导入的命名空间 (Visual Basic)。 使用表达式目录树启用高级 LINQ 功能 z 如果已引用 System.Core.dll,则添加 System.Linq.Expressions 的 using 指令或 Imports 语句。 有关更多信息,请参见表达式目录树。 使用 LINQ to XML 1. 如有必要,按照本主题中前面介绍的步骤添加对 System.Core.dll 的引用和 System.Linq 的 using 指令 或 Imports 语句。 2. 添加对 System.Xml.Linq 的引用。 3. 添加 System.Xml.Linq 的 using 指令或 Imports 语句。 使用 LINQ to SQL 1. 如有必要,按照本主题中前面介绍的步骤添加对 System.Core.dll 的引用和 System.Linq 的 using 指令 或 Imports 语句。 2. 添加对 System.Data.Linq 的引用。 3. 添加 System.Data.Linq 的 using 指令或 Imports 语句,或者其他 System.Data.Linq 命名空间之一, 具体取决于您特定项目的要求。 有关更多信息,请参见 LINQ to SQL。 使用 LINQ to Dataset 1. 如有必要,按照本主题中前面介绍的步骤添加对 System.Core.dll 的引用和 System.Linq 的 using 指令 或 Imports 语句。 注意: 默认情况下,为 Visual Basic 项目提供此功能。 有关更多信息,请参见 LINQ to XML。 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/a929e653-09a3-44be-... 请参见 2. 为 LINQ to DataSet 功能添加对 System.Data.DataSetExtensions.dll 的引用。添加对 System.Data.dll 的引用(如果尚不存在)。 3. 为 System.Data 添加 using 指令或 Imports 语句,根据需要也可以为 System.Data.Common、 System.Data.SqlClient 添加,具体取决于您连接到数据库的方式。 有关更多信息,请参见 LINQ to DataSet。 概念 语言集成查询 (LINQ) using 指令(C# 参考) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/a929e653-09a3-44be-... 全部折叠 代码:C# 语言集成查询 (LINQ) 对 LINQ 的 Visual Studio IDE 和工具支持 请参见 发送反馈意见 Visual Studio 2008 集成开发环境 (IDE) 提供了下列支持 LINQ 应用程序开发的功能: 对象关系设计器 SQLMetal 命令行工具 支持 LINQ 的代码编辑器 Visual Studio 调试器支持 请参见 对象关系设计器是一种可视化设计工具,可在 LINQ to SQL 应用程序中使用该工具并通过 C# 或 Visual Basic 生成表示基础数据库中的关系数据的类。有关更多信息,请参见对象关系设计器(O/R 设计器)。 SQLMetal 是一种可在生成过程中使用的命令行工具,该工具可从现有数据库生成类以供在 LINQ to SQL 应用 程序中使用。有关更多信息,请参见代码生成工具 (SqlMetal.exe)。 C# 和 Visual Basic 代码编辑器通过新的 IntelliSense 和格式设置功能广泛地支持 LINQ。有关更多信息,请参 见 Visual C# 中的新增功能和 Visual Basic 中的新增功能。 Visual Studio 调试器支持调试查询表达式。有关更多信息,请参见调试 LINQ。 概念 语言集成查询 (LINQ) 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,1/1(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/2bee46c4-bf12-43a5-a... 全部折叠 代码:C# 语言集成查询 (LINQ) LINQ 常规编程指南 发送反馈意见 本节包含有关如何使用 LINQ 进行编程的信息,包括标准查询运算符、表达式目录树在 LINQ 中的用法以及自定义 LINQ 提供程序。 本节内容 标准查询运算符概述 提供标准查询运算符简介,还提供包含有关各种类型的查询操作的更多信息的主题链接。 LINQ 中的表达式目录树 讨论表达式目录树在 LINQ 中的用法。 启用数据源以进行 LINQ 查询 介绍自定义 LINQ 提供程序和其他扩展 LINQ 的方法。 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,1/1(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/609c7a6b-cbdd-429d-... 全部折叠 代码:C# 语言集成查询 (LINQ) 标准查询运算符概述 请参见 发送反馈意见 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法。大多数这些方法都在序列上运行,其中的序列是一个 对象,其类型实现了 IEnumerable(T) 接口或 IQueryable(T) 接口。标准查询运算符提供了包括筛选、投影、聚合、 排序等功能在内的查询功能。 共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable(T) 的对象上运行,另一组在类型为 IQueryable(T) 的 对象上运行。构成每组运算符的方法分别是 Enumerable 和 Queryable 类的静态成员。这些方法被定义为作为方法 运行目标的类型的“扩展方法”。 这意味着可以使用静态方法语法或实例方法语法来调用它们。 此外,许多标准查询运算符方法运行所针对的类型不是基于 IEnumerable(T) 或 IQueryable(T) 的类型。Enumerable 类型定义两个此类方法,这些方法都在类型为 IEnumerable 的对象上运行。利用这些方法(Cast(TResult) (IEnumerable) 和 OfType(TResult)(IEnumerable)),您将能够在 LINQ 模式中查询非参数化或非泛型集合。这些方 法通过创建一个强类型的对象集合来实现这一点。Queryable 类定义两个类似的方法(Cast(TResult)(IQueryable) 和 OfType(TResult)(IQueryable)),这些方法在类型为 Queryable 的对象上运行。 各个标准查询运算符在执行时间上有所不同,具体情况取决于它们是返回单一值还是值序列。返回单一值的方法 (例如 Average 和 Sum)会立即执行。返回序列的方法会延迟查询执行,并返回一个可枚举的对象。 对于在内存中集合上运行的方法(即扩展 IEnumerable(T) 的那些方法),返回的可枚举对象将捕获传递到方法的参 数。在枚举该对象时,将使用查询运算符的逻辑,并返回查询结果。 与之相反,扩展 IQueryable(T) 的方法不会实现任何查询行为,但会生成一个表示要执行的查询的表达式目录树。 查询处理由源 IQueryable(T) 对象处理。 可以在一个查询中将对查询方法的调用链接在一起,这就使得查询的复杂性可能会变得不确定。 下面的代码示例演示如何使用标准查询运算符来获取有关序列的信息。 查询表达式语法 C# 复制代码 string sentence = "the quick brown fox jumps over the lazy dog"; // Split the string into individual words to create a collection. string[] words = sentence.Split(' '); // Using query expression syntax. var query = from word in words group word.ToUpper() by word.Length into gr orderby gr.Key select new { Length = gr.Key, Words = gr }; // Using method-based query syntax. var query2 = words. GroupBy(w => w.Length, w => w.ToUpper()). Select(g => new { Length = g.Key, Words = g }). OrderBy(o => o.Length); foreach (var obj in query) { Console.WriteLine("Words of length {0}:", obj.Length); foreach (string word in obj.Words) Console.WriteLine(word); } // This code example produces the following output: // // Words of length 3: // THE // FOX // THE // DOG // Words of length 4: // OVER // LAZY // Words of length 5: // QUICK // BROWN // JUMPS 某些使用更频繁的标准查询运算符具有专用的 C# 和 Visual Basic 语言关键字语法,利用这些语法,将可以在 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/24cda21e-8af8-4632-... 扩展标准查询运算符 相关章节 请参见 “查询表达式”中调用这些运算符。 有关具有专用关键字及其对应语法的标准查询运算符的更多信息,请参 见标准查询运算符的查询表达式语法。 通过创建适合于目标域或技术的特定于域的方法,您可以增大标准查询运算符的集合。也可以用您自己的实现 来替换标准查询运算符,这些实现提供诸如远程计算、查询转换和优化等附加服务。有关示例,请参见 AsEnumerable(TSource)。 通过以下链接可转到一些主题,这些主题基于功能提供有关各种标准查询运算符的附加信息。 对数据进行排序 Set 操作 筛选数据 限定符运算 投影运算 数据分区 联接运算 对数据进行分组 生成运算 相等运算 元素操作 转换数据类型 串联运算 聚合运算 概念 LINQ 查询简介 标准查询运算符的查询表达式语法 扩展方法(C# 编程指南) 扩展方法 (Visual Basic) 参考 Enumerable Queryable 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/24cda21e-8af8-4632-... 全部折叠 代码:C# 语言集成查询 (LINQ) 标准查询运算符的查询表达式语法 请参见 发送反馈意见 某些使用更频繁的标准查询运算符具有专用的 C# 和 Visual Basic 语言关键字语法,利用这些语法,将可以在“查 询表达式”中调用这些运算符。 与“基于方法”的查询表达形式相比,查询表达式是一种不同的、可读性更好的查 询表达形式。 在编译时,查询表达式子句将被转换为对查询方法的调用。 查询表达式语法表 下表列出了具有等效查询表达式子句的标准查询运算符。C# 和 Visual Basic 编程语言没有为相同方法提供专 用查询表达式语法。下表列出了同时适用于这两种语言的语法。 方法 C# 查询表达式语法 Visual Basic 查询表达式语法 All(TSource)(IEnumerable(TSource), Func(TSource, Boolean)) 不适用 Aggregate … In … Into All (…) (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Any(TSource)(IEnumerable(TSource)) 不适用 Aggregate … In … Into Any() (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Average(IEnumerable(Decimal)) 不适用 Aggregate … In … Into Average() (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Cast(TResult)(IEnumerable) 使用显式类型化的范围 变量,例如: from int i in numbers (有关更多信息,请参 见 from 子句(C# 参 考)。) From … As … (有关更多信息,请参见 From 子句 (Visual Basic)。) Count(TSource)(IEnumerable(TSource)) 不适用 Aggregate … In … Into Count () (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Distinct(TSource)(IEnumerable (TSource)) 不适用 Distinct (有关更多信息,请参见 Distinct 子句 (Visual Basic)。) GroupBy() group … by - 或 - group … by … into … (有关更多信息,请参 见 group 子句(C# 参 考)。) Group … By … Into … (有关更多信息,请参见 Group By 子句 (Visual Basic)。) GroupJoin(TOuter, TInner, TKey, TResult)(IEnumerable(TOuter), IEnumerable(TInner), Func(TOuter, TKey), Func(TInner, TKey), Func (TOuter, IEnumerable(TInner), TResult)) join … in … on … equals … into … (有关更多信息,请参 见 join 子句(C# 参 考)。) Group Join … In … On … (有关更多信息,请参见 Group Join 子句 (Visual Basic)。) Join(TOuter, TInner, TKey, TResult) (IEnumerable(TOuter), IEnumerable (TInner), Func(TOuter, TKey), Func join … in … on … equals … From x In …, y In … Where x.a = b.a 页码,1/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/7c427bbc-450e-44ef-a... (TInner, TKey), Func(TOuter, TInner, TResult)) (有关更多信息,请参 见 join 子句(C# 参 考)。) - 或 - Join … [As …]In … On … (有关更多信息,请参见 Join 子 句 (Visual Basic)。) LongCount(TSource)(IEnumerable (TSource)) 不适用 Aggregate … In … Into LongCount() (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Max(IEnumerable(Decimal)) 不适用 Aggregate … In … Into Max() (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Min(IEnumerable(Decimal)) 不适用 Aggregate … In … Into Min() (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) OrderBy(TSource, TKey)(IEnumerable (TSource), Func(TSource, TKey)) orderby (有关更多信息,请参 见 orderby 子句(C# 参考)。) Order By (有关更多信息,请参见 Order By 子句 (Visual Basic)。) OrderByDescending(TSource, TKey) (IEnumerable(TSource), Func(TSource, TKey)) orderby … descending (有关更多信息,请参 见 orderby 子句(C# 参考)。) Order By … Descending (有关更多信息,请参见 Order By 子句 (Visual Basic)。) Select select (有关更多信息,请参 见 select 子句(C# 参 考)。) Select (有关更多信息,请参见 Select 子句 (Visual Basic)。) SelectMany 多个 from 子句。 (有关更多信息,请参 见 from 子句(C# 参 考)。) 多个 From 子句 (有关更多信息,请参见 From 子句 (Visual Basic)。) Skip(TSource)(IEnumerable(TSource), Int32) 不适用 Skip (有关更多信息,请参见 Skip 子 句 (Visual Basic)。) SkipWhile 不适用 Skip While (有关更多信息,请参见 Skip While 子句 (Visual Basic)。) Sum(IEnumerable(Decimal)) 不适用 Aggregate … In … Into Sum() (有关更多信息,请参见 Aggregate 子句 (Visual Basic)。) Take(TSource)(IEnumerable(TSource), Int32) 不适用 Take (有关更多信息,请参见 Take 子句 (Visual Basic)。) TakeWhile 不适用 Take While (有关更多信息,请参见 Take While 子句 (Visual Basic)。) ThenBy(TSource, TKey) (IOrderedEnumerable(TSource), Func (TSource, TKey)) orderby …, … (有关更多信息,请参 见 orderby 子句(C# 参考)。) Order By …, … (有关更多信息,请参见 Order By 子句 (Visual Basic)。) 页码,2/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/7c427bbc-450e-44ef-a... 请参见 ThenByDescending(TSource, TKey) (IOrderedEnumerable(TSource), Func (TSource, TKey)) orderby …, … descending (有关更多信息,请参 见 orderby 子句(C# 参考)。) Order By …, … Descending (有关更多信息,请参见 Order By 子句 (Visual Basic)。) Where where (有关更多信息,请参 见 where 子句(C# 参 考)。) Where (有关更多信息,请参见 Where 子句 (Visual Basic)。) 概念 标准查询运算符概述 参考 Enumerable Queryable 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,3/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/7c427bbc-450e-44ef-a... 全部折叠 代码:C# 语言集成查询 (LINQ) 对数据进行排序 请参见 发送反馈意见 排序操作按一个或多个属性对序列的元素进行排序。第一个排序条件对元素执行主要排序。通过指定第二个排序条件,可以对各个 主要排序组中的元素进行排序。 下图演示对一个字符序列执行按字母排序操作的结果。 下面一节中列出了对数据进行排序的标准查询运算符方法。 方法 查询表达式语法示例 方法名 说明 C# 查询表达式语法 Visual Basic 查询表达式语法 更多信息 OrderBy 按升 序对 值进 行排 序。 orderby Order By Enumerable.OrderBy Queryable.OrderBy OrderByDescending 按降 序对 值进 行排 序。 orderby … descending Order By … Descending Enumerable.OrderByDescending Queryable.OrderByDescending ThenBy 按升 序执 行次 要排 序。 orderby …, … Order By …, … Enumerable.ThenBy Queryable.ThenBy ThenByDescending 按降 序执 行次 要排 序。 orderby …, … descending Order By …, … Descending Enumerable.ThenByDescending Queryable.ThenByDescending Reverse 颠倒 集合 中的 元素 的顺 序。 不适用。 不适用。 Enumerable.Reverse(TSource) Queryable.Reverse(TSource) 主要排序示例 主要升序排序 下面的示例演示如何在 LINQ 查询中使用 orderby(在 Visual Basic 中为 Order By)子句来按字符串长度对数组中的字符 串进行升序排序。 C# 复制代码 string[] words = { "the", "quick", "brown", "fox", "jumps" }; IEnumerable query = from word in words orderby word.Length select word; foreach (string str in query) Console.WriteLine(str); /* This code produces the following output: the 页码,1/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/6d76e2d7-b418-49b5-... 主要降序排序 下一个示例演示如何在 LINQ 查询中使用 orderby descending(在 Visual Basic 中为 Order By Descending)子句来按 字符串的第一个字母对字符串进行降序排序。 次要排序示例 次要升序排序 下面的示例演示如何在 LINQ 查询中使用 orderby(在 Visual Basic 中为 Order By)子句来对数组中的字符串执行主要和 次要排序。首先按字符串长度,其次按字符串的第一个字母,对字符串进行升序排序。 次要降序排序 下一个示例演示如何在 LINQ 查询中使用 orderby descending(在 Visual Basic 中为 Order By Descending)子句来按 升序执行主要排序,按降序执行次要排序。首先按字符串长度,其次按字符串的第一个字母,对字符串进行排序。 fox quick brown jumps */ C# 复制代码 string[] words = { "the", "quick", "brown", "fox", "jumps" }; IEnumerable query = from word in words orderby word.Substring(0, 1) descending select word; foreach (string str in query) Console.WriteLine(str); /* This code produces the following output: the quick jumps fox brown */ C# 复制代码 string[] words = { "the", "quick", "brown", "fox", "jumps" }; IEnumerable query = from word in words orderby word.Length, word.Substring(0, 1) select word; foreach (string str in query) Console.WriteLine(str); /* This code produces the following output: fox the brown jumps quick */ C# 复制代码 string[] words = { "the", "quick", "brown", "fox", "jumps" }; IEnumerable query = from word in words orderby word.Length, word.Substring(0, 1) descending select word; foreach (string str in query) Console.WriteLine(str); /* This code produces the following output: the fox quick jumps brown 页码,2/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/6d76e2d7-b418-49b5-... 有关如何对数据进行排序的更多信息 请参见 */ Topic Location How to: Order the Results of a Join Clause C# Programmer's Reference How to: Sort a Collection Visual Basic Language Reference How to: Sort or Filter Text Data by Any Word or Field (LINQ) Language-Integrated Query (LINQ) orderby clause C# Programmer's Reference orderby 子句 C# 程序员参考 如何:对 Join 子句的结果进行排序 C# 程序员参考 如何:对集合进行排序 Visual Basic 语言参考 如何:按任意词或字段对文本数据进行排序或筛选 (LINQ) 语言集成查询 (LINQ) 概念 标准查询运算符概述 orderby 子句(C# 参考) Order By 子句 (Visual Basic) 参考 System.Linq 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,3/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/6d76e2d7-b418-49b5-... 全部折叠 代码:C# 语言集成查询 (LINQ) Set 操作 请参见 发送反馈意见 LINQ 中的 Set 操作是指根据相同或不同集合(或集)中是否存在等效元素来生成结果集的查询操作。 下面一节中列出了执行 Set 操作的标准查询运算符方法。 方法 比较 Set 操作 方法名 说明 C# 查询表达式语法 Visual Basic 查询表达式语法 更多信息 Distinct 从集合移除 重复值。 不适用。 Distinct Enumerable.Distinct Queryable.Distinct Except 返回差集, 差集是指位 于一个集合 但不位于另 一个集合的 元素。 不适用。 不适用。 Enumerable.Except Queryable.Except Intersect 返回交集, 交集是指同 时出现在两 个集合中的 元素。 不适用。 不适用。 Enumerable.Intersect Queryable.Intersect Union 返回并集, 并集是指位 于两个集合 中任一集合 的唯一的元 素。 不适用。 不适用。 Enumerable.Union Queryable.Union Distinct 下图演示 Enumerable.Distinct 方法对字符序列的行为。返回的序列包含输入序列的唯一元素。 Except 下图演示 Enumerable.Except 的行为。返回的序列只包含位于第一个输入序列但不位于第二个输入序列的元 素。 Intersect 下图演示 Enumerable.Intersect 的行为。返回的序列包含两个输入序列共有的元素。 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/93a6e634-7e1a-40a5-... 查询表达式语法示例 有关如何执行 Set 操作的更多信息 请参见 Union 下图演示对两个字符序列执行的联合操作。返回的序列包含两个输入序列的唯一的元素。 下面的示例在 LINQ 查询中使用 Distinct 子句(仅在 Visual Basic 中可用)来返回整数列表中的唯一数字。 Topic Location How to: Combine and Compare String Collections (LINQ) Language-Integrated Query (LINQ) How to: Find the Set Difference Between Two Lists (LINQ) Language-Integrated Query (LINQ) 如何:查找两个列表之间的差集 (LINQ) 语言集成查询 (LINQ) 如何:组合和比较字符串集合 (LINQ) 语言集成查询 (LINQ) 概念 标准查询运算符概述 Distinct 子句 (Visual Basic) 参考 System.Linq 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/93a6e634-7e1a-40a5-... 全部折叠 代码:C# 语言集成查询 (LINQ) 筛选数据 请参见 发送反馈意见 筛选指将结果集限制为只包含那些满足指定条件的元素的操作。它又称为选择。 下图演示了对字符序列进行筛选的结果。筛选操作的谓词指定字符必须为“A”。 下面一节中列出了执行选择的标准查询运算符方法。 方法 查询表达式语法示例 有关如何筛选数据的更多信息 方法名 说明 C# 查询表达式语法 Visual Basic 查询表达式语法 更多信息 OfType 根据值强制转 换为指定类型 的能力选择 值。 不适用。 不适用。 Enumerable.OfType (TResult) Queryable.OfType (TResult) Where 选择基于谓词 函数的值。 where Where Enumerable.Where Queryable.Where 下面的示例使用 where 子句(在 C# 中)或 Where 子句(在 Visual Basic 中)来从数组中筛选那些具有特 定长度的字符串。 C# 复制代码 string[] words = { "the", "quick", "brown", "fox", "jumps" }; IEnumerable query = from word in words where word.Length == 3 select word; foreach (string str in query) Console.WriteLine(str); /* This code produces the following output: the fox */ Topic Location How to: Dynamically Specify Predicate Filters at Runtime C# Programmer's Reference How to: Filter Query Results Visual Basic Language Reference How to: Query An Assembly's Metadata with Reflection Language-Integrated Query (LINQ) How to: Query for Files with a Specified Attribute or Name Language-Integrated Query (LINQ) How to: Sort or Filter Text Data by Any Word or Field (LINQ) Language-Integrated Query (LINQ) where clause C# Programmer's Reference where 子句 C# 程序员参考 如何:使用反射查询程序集的元数据 语言集成查询 (LINQ) 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/cee88d0f-31aa-4c60-9... 请参见 如何:在运行时动态指定谓词筛选器 C# 程序员参考 如何:按任意词或字段对文本数据进行排序或筛选 (LINQ) 语言集成查询 (LINQ) 如何:查询具有指定属性或名称的文件 语言集成查询 (LINQ) 如何:筛选查询结果 Visual Basic 语言参考 概念 标准查询运算符概述 where 子句(C# 参考) Where 子句 (Visual Basic) 参考 System.Linq 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/cee88d0f-31aa-4c60-9... 全部折叠 代码:C# 语言集成查询 (LINQ) 限定符运算 请参见 发送反馈意见 限定符运算返回一个 Boolean 值,该值指示序列中是否有一些元素满足条件或是否所有元素都满足条件。 下图描述了两个不同源序列上的两个不同限定符运算。第一个运算询问是否有一个或多个元素为字符“A”,结果为 true。第二个运算询问是否所有元素都为字符“A”,结果为 true。 以下部分列出了执行限定符运算的标准查询运算符方法。 方法 查询表达式语法示例 有关如何执行限定运算的更多信息 请参见 方法名 说明 C# 查询表达式语法 Visual Basic 查询表达式语法 更多信息 All 确定是否 序列中的 所有元素 都满足条 件。 不适用。 Aggregate … In … Into All(…) Enumerable.All (TSource) Queryable.All (TSource) Any 确定序列 中是否有 元素满足 条件。 不适用。 Aggregate … In … Into Any() Enumerable.Any Queryable.Any Contains 确定序列 是否包含 指定的元 素。 不适用。 不适用。 Enumerable.Contains Queryable.Contains 下面这些示例将 Visual Basic 中的 Aggregate 子句用作 LINQ 查询中的筛选条件的一部分。 第一个示例使用 Aggregate 子句和 All(TSource) 扩展方法从集合中返回其宠物的年龄全都大于指定年龄的人 员。 第二个示例使用 Aggregate 子句和 Any 扩展方法从集合中返回那些至少有一只宠物的年龄大于指定年龄的 人员。 Topic Location How to: Query for Sentences that Contain a Specified Set of Words (LINQ) Language-Integrated Query (LINQ) 如何:查询包含一组指定单词的句子 (LINQ) 语言集成查询 (LINQ) 概念 标准查询运算符概述 Aggregate 子句 (Visual Basic) 页码,1/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/0917704d-c4c0-40aa-... 如何:在运行时动态指定谓词筛选器(C# 编程指南) 参考 System.Linq 发送反馈意见,就此主题向 Microsoft 发送反馈意见。 页码,2/2(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/0917704d-c4c0-40aa-... 全部折叠 代码:C# 语言集成查询 (LINQ) 投影运算 请参见 发送反馈意见 投影是指将对象转换为一种新形式的操作,该形式通常只包含那些将随后使用的属性。通过使用投影,您可以构建依据每个对象生成的新 类型。您可以映射属性,并对该属性执行数学函数。还可以在不更改原始对象的情况下映射该对象。 下面一节中列出了执行投影的标准查询运算符方法。 方法 查询表达式语法示例 Select 与 SelectMany 方法名 说明 C# 查询表达式语法 Visual Basic 查询表达式语法 更多信息 Select 映射基于转换函数的值。 select Select Enumerable.Select Queryable.Select SelectMany 映射基于转换函数的值序 列,然后将它们展平为一个 序列。 使用多个 from 子 句 使用多个 From 子句 Enumerable.SelectMany Queryable.SelectMany Select 下面的示例使用 C# 中的 select 子句或 Visual Basic 中的 Select 子句来映射字符串列表中每个字符串的第一个字母。 SelectMany 下面的示例使用多个 from 子句(在 C# 中)或 From 子句(在 Visual Basic 中)来映射字符串列表中每个字符串中的每个单词。 C# 复制代码 List words = new List() { "an", "apple", "a", "day" }; var query = from word in words select word.Substring(0, 1); foreach (string s in query) Console.WriteLine(s); /* This code produces the following output: a a a d */ C# 复制代码 List phrases = new List() { "an apple a day", "the quick brown fox" }; var query = from phrase in phrases from word in phrase.Split(' ') select word; foreach (string s in query) Console.WriteLine(s); /* This code produces the following output: an apple a day the quick brown fox */ Select() 和 SelectMany() 的工作都是依据源值生成一个或多个结果值。Select() 为每个源值生成一个结果值。因此,总体结果是 一个与源集合具有相同元素数目的集合。与之相反,SelectMany() 将生成单一总体结果,其中包含来自每个源值的串联子集合。作 为参数传递到 SelectMany() 的转换函数必须为每个源值返回一个可枚举值序列。然后,SelectMany() 将串联这些可枚举序列以创 建一个大的序列。 下面两个插图演示了这两个方法的操作之间的概念性区别。在每种情况下,假定选择器(转换)函数从每个源值中选择一个由花卉 数据组成的数组。 下图描述 Select() 如何返回一个与源集合具有相同元素数目的集合。 页码,1/3(W)w 2008/3/17ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_linq/html/fe2c07ed-95ac-4276-8... 下图描述 SelectMany() 如何将中间数组序列串联为一个最终结果值,其中包含每个中间数组中的每个值。 代码示例 下面的示例比较 Select() 和 SelectMany() 的行为。代码将通过从源集合的每个花卉名称列表中提取前两项来创建一个“花束”。 在此示例中,转换函数 Select(TSource, TResult)(IEnumerable(TSource), Func(TSource, TResult)) 使用的“单一值”本身就是一个值 集合。这需要额外的 foreach(Visual Basic 中为 For Each)循环,以便枚举每个子序列中的每个字符串。 C# 复制代码 class Bouquet { public List Flowers { get; set; } } static void SelectVsSelectMany() { List bouquets = new List() { new Bouquet { Flowers = new List { "sunflower", "daisy", "daffodil", "larkspur" }}, new Bouquet{ Flowers = new List { "tulip", "rose", "orchid" }}, new Bouquet{ Flowers = new List { "gladiolis", "lily", "snapdragon", "aster", "protea" }}, new Bouquet{ Flowers = new List { "larkspur", "lilac", "iris", "dahlia" }} }; // *********** Select *********** IEnumerable
- > query1 = bouquets.Select(bq => bq.Flowers); // ********* SelectMany ********* IEnumerable
- abc
- def
- abc
- abc
- def
- abc