xml地图|网站地图|网站标签 [设为首页] [加入收藏]

开始使用

走进 LINQ 的世界

[C#] 开始使用 LINQ,

 

  在此之前曾发表过三篇关于 LINQ 的随笔:

    进阶:《LINQ 标准查询操作概述》(强烈推荐)

    技巧:《Linq To Objects - 如何操作字符串》 和 《Linq To Objects - 如何操作文件目录》

  现在,自己打算再整理一篇关于 LINQ 入门的随笔,也是图文并茂的哦。

 

开始使用 LINQ 

  在此之前曾发表过三篇关于 LINQ 的随笔:

    进阶:《LINQ 标准查询操作概述》(强烈推荐)

    技巧:《Linq To Objects - 如何操作字符串》 和 《Linq To Objects

  • 如何操作文件目录》

  现在,自己打算再整理一篇关于 LINQ 入门的随笔。为了避免篇幅过长,最终还是选择将代码折叠起来。

  • LINQ

目录

  • LINQ 简介
  • 介绍 LINQ 查询
  • LINQ 基本查询操作
  • 使用 LINQ 进行数据转换
  • LINQ 查询操作的类型关系
  • LINQ 中的查询语法和方法语法

 

  语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的一项创新功能。

  传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或 IntelliSense 支持。此外,您还必须针对以下各种数据源学习一种不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等等。 通过LINQ, 您可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。

必威 1

  

  在 Visual Studio 中,可以为以下数据源编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集,以及支持 IEnumerable 或泛型 IEnumerable<T> 接口的任意对象集合。   使用要求:项目 ≥ .NET Framework 3.5 。  

     语言集成查询 (LINQ) 是 Visual Studio 2008 中引入的一组功能,它在对象领域和数据领域之间架起了一座桥梁。可为 C# 和 Visual Basic 语言语法提供强大的查询功能。 LINQ 引入了标准、易学的数据查询和更新模式,该技术可以扩展为几乎支持任何类型的数据存储。Visual Studio 包含 LINQ 提供程序的程序集,借助这些程序集,就能将 LINQ 用于 .NET Framework 集合、SQL Server 数据库、ADO.NET 数据集和 XML 文档。

LINQ 简介

  语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的一项创新功能。

  传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或 IntelliSense 支持。此外,您还必须针对以下各种数据源学习一种不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等等。 通过LINQ, 您可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询。

必威 2

  

  在 Visual Studio 中,可以为以下数据源编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集,以及支持 IEnumerable 或泛型 IEnumerable<T> 接口的任意对象集合。

  使用要求:项目 ≥ .NET Framework 3.5 。

 

目录

  • 介绍 LINQ 查询
  • LINQ 基本查询操作
  • 使用 LINQ 进行数据转换
  • LINQ 查询操作的类型关系
  • LINQ 中的查询语法和方法语法

 

  • LINQ应用场景
    • LINQ to Object:针对数组和集合
    • LINQ to XML:针对XML文档
    • LINQ to DataSet:针对ADO的DataSet对象
    • LINQ to Entites:针对EF
    • Parallel LINQ:并行处理LINQ查询返回的数据
  • LINQ 查询

一、介绍 LINQ 查询

  查询是一种从数据源检索数据的表达式。随着时间的推移,人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。LINQ 通过提供一种跨数据源和数据格式使用数据的一致模型,简化了这一情况。在 LINQ 查询中,始终会用到对象。可以使用相同的编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。  

 

一、介绍 LINQ 查询

  查询是一种从数据源检索数据的表达式。随着时间的推移,人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。LINQ 通过提供一种跨数据源和数据格式使用数据的一致模型,简化了这一情况。在 LINQ 查询中,始终会用到对象。可以使用相同的编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。  

     查询是一种从数据源检索数据的表达式。 查询通常用专门的查询语言来表示。 随着时间的推移,人们已经为各种数据源开发了不同的语言;例如,用于关系数据库的 SQL 和用于 XML 的 XQuery。 因此,开发人员不得不针对他们必须支持的每种数据源或数据格式而学习新的查询语言。 LINQ 通过提供一种跨各种数据源和数据格式使用数据的一致模型,简化了这一情况。 在 LINQ 查询中,始终会用到对象。 可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。

  1.1 查询操作的三个部分

  操作三部曲:①取数据源 ②创建查询 ③执行查询

必威 3必威 4

 1 internal class Program
 2 {
 3         private static void Main(string[] args)
 4         {
 5             //1.获取数据源
 6             var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
 7 
 8             //2.创建查询
 9             var numQuery =
10                 from num in nums
11                 where (num % 2) == 0
12                 select num;
13 
14             //3.执行查询
15             foreach (var num in numQuery)
16             {
17                 Console.WriteLine("{0}", num);
18             }
19         }
20 }

View Code

必威 5

 

   下图显示了完整的查询操作。在 LINQ 中,查询的执行与查询本身截然不同;换句话说,查询本身指的是只创建查询变量,不检索任何数据。

必威 6

  

  1.1 查询操作的三个部分

  操作三部曲:①取数据源 ②创建查询 ③执行查询

必威 7 1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 //1.获取数据源 6 var nums = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; 7 8 //2.创建查询 9 var numQuery = 10 from num in nums 11 where (num % 2) == 0 12 select num; 13 14 //3.执行查询 15 foreach (var num in numQuery) 16 { 17 Console.WriteLine("{0}", num); 18 } 19 } 20 } View Code

必威 8

 

   下图显示了完整的查询操作。在 LINQ 中,查询的执行与查询本身截然不同;换句话说,查询本身指的是只创建查询变量,不检索任何数据。

必威 9

  

必威 10

  1.2 数据源

  在上一个示例中,由于数据源是数组,因此它隐式支持泛型 IEnumerable<T> 接口。支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>)的类型称为可查询类型。  

  可查询类型不需要进行修改或特殊处理就可以用作 LINQ 数据源。如果源数据还没有作为可查询类型出现在内存中,则 LINQ 提供程序必须以此方式表示源数据。例如,LINQ to XML 将 XML 文档加载到可查询的 XElement 类型中:

  //从 XML 中创建数据源
  //using System.Xml.Linq;
  var contacts = XElement.Load(@"c:xxx.xml");

  

  在 LINQ to SQL 中,首先需要创建对象关系映射。 针对这些对象编写查询,然后由 LINQ to SQL 在运行时处理与数据库的通信。

必威 11必威 12

1     var  db = new Northwnd(@"c:northwnd.mdf");
2     
3     //查询在伦敦的客户
4     var custQuery =
5         from cust in db.Customers
6         where cust.City == "London"
7         select cust;

Customers 表示数据库中的特定表

 

  1.2 数据源

  在上一个示例中,由于数据源是数组,因此它隐式支持泛型 IEnumerable<T> 接口。支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>)的类型称为可查询类型。  

  可查询类型不需要进行修改或特殊处理就可以用作 LINQ 数据源。如果源数据还没有作为可查询类型出现在内存中,则 LINQ 提供程序必须以此方式表示源数据。例如,LINQ to XML 将 XML 文档加载到可查询的 XElement 类型中:

  //从 XML 中创建数据源
  //using System.Xml.Linq;
  var contacts = XElement.Load(@"c:xxx.xml");

  

  在 LINQ to SQL 中,首先需要创建对象关系映射。 针对这些对象编写查询,然后由 LINQ to SQL 在运行时处理与数据库的通信。

必威 131 var db = new Northwnd(@"c:northwnd.mdf"); 2 3 //查询在伦敦的客户 4 var custQuery = 5 from cust in db.Customers 6 where cust.City == "London" 7 select cust; Customers 表示数据库中的特定表

 

 

  1.3 查询

  查询指定要从数据源中检索的信息。 查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化。 查询存储在查询变量中,并用查询表达式进行初始化。

  之前的示例中的查询是从整数数组中返回所有的偶数。 该查询表达式包含三个子句:fromwhere 和 select。(如果您熟悉 SQL,您会注意到这些子句的顺序与 SQL 中的顺序相反。)from 子句指定数据源,where 子句指定应用筛选器,select 子句指定返回的元素的类型。 目前需要注意的是,在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。 它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。

 

  1.3 查询

  查询指定要从数据源中检索的信息。 查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化。 查询存储在查询变量中,并用查询表达式进行初始化。

  之前的示例中的查询是从整数数组中返回所有的偶数。 该查询表达式包含三个子句:fromwhere 和 select。(如果您熟悉 SQL,您会注意到这些子句的顺序与 SQL 中的顺序相反。)from 子句指定数据源,where 子句指定应用筛选器,select 子句指定返回的元素的类型。 目前需要注意的是,在 LINQ 中,查询变量本身不执行任何操作并且不返回任何数据。 它只是存储在以后某个时刻执行查询时为生成结果而必需的信息。  

    • 获取数据源

  1.4 查询执行

  1.4 查询执行

     LINQ语句是在 foreach 语句中执行查询,而 foreach 要求使用 IEnumerable 或 IEnumerable<T>。支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>)的类型称为“可查询类型”。

  1.延迟执行

    如前所述,查询变量本身只是存储查询命令。  实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。 此概念称为“延迟执行”。

  1.延迟执行

    如前所述,查询变量本身只是存储查询命令。  实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。 此概念称为“延迟执行”。

Northwnd db = new Northwnd(@"c:northwnd.mdf");

  2.强制立即执行

    对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。CountMaxAverage 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。 

必威 14必威 15

1     var numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
2 
3     var evenNumQuery =
4         from num in numbers
5         where (num % 2) == 0
6         select num;
7 
8     var evenNumCount = evenNumQuery.Count();

View Code

必威 16

 

  若要强制立即执行任意查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法。

必威 17必威 18

1     var numQuery2 =
2            (from num in numbers
3             where (num % 2) == 0
4             select num).ToList();
5 
6     var numQuery3 =
7           (from num in numbers
8            where (num % 2) == 0
9             select num).ToArray();

View Code

 

  此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。但是,通过调用 ToList 或 ToArray,也可以将所有数据缓存在单个集合对象中。 

 

  2.强制立即执行

    对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。CountMaxAverage 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。 

必威 191 var numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 }; 2 3 var evenNumQuery = 4 from num in numbers 5 where (num % 2) == 0 6 select num; 7 8 var evenNumCount = evenNumQuery.Count(); View Code

1 var numQuery2 = 2 (from num in numbers 3 where (num % 2) == 0 4 select num).ToList(); 5 6 var numQuery3 = 7 (from num in numbers 8 where (num % 2) == 0 9 select num).ToArray(); View Code

 

  此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。但是,通过调用 ToList 或 ToArray,也可以将所有数据缓存在单个集合对象中。 

 

    • 创建查询

二、基本 LINQ 查询操作

二、基本 LINQ 查询操作

     查询指定要从数据源中检索的信息。查询还可以指定在返回这些信息之前如何对其进行排序、分组和结构化。查询存储在查询变量中,并用查询表达式进行初始化。

  2.1 获取数据源:from

  在 LINQ 查询中,第一步是指定数据源。像在大多数编程语言中一样,必须先声明变量,才能使用它。在 LINQ 查询中,最先使用 from 子句的目的是引入数据源和范围变量。

必威 20必威 21

1     //queryAllCustomers 是 IEnumerable<Cutsomer> 类型
2     //数据源 (customers) 和范围变量 (cust)
3     var queryAllCustomers = from cust in customers
4                                            select cust;

View Code

  范围变量类似于 foreach 循环中的迭代变量,但在查询表达式中,实际上不发生迭代。执行查询时,范围变量将用作对 customers 中的每个后续元素的引用。因为编译器可以推断 cust 的类型,所以您不必显式指定此类型。

 

  2.1 获取数据源:from

  在 LINQ 查询中,第一步是指定数据源。像在大多数编程语言中一样,必须先声明变量,才能使用它。在 LINQ 查询中,最先使用 from 子句的目的是引入数据源和范围变量。

必威 221 //queryAllCustomers 是 IEnumerable<Cutsomer> 类型 2 //数据源 (customers) 和范围变量 (cust) 3 var queryAllCustomers = from cust in customers 4 select cust; View Code

  范围变量类似于 foreach 循环中的迭代变量,但在查询表达式中,实际上不发生迭代。执行查询时,范围变量将用作对 customers 中的每个后续元素的引用。因为编译器可以推断 cust 的类型,所以您不必显式指定此类型。

 

    • 执行查询
      • 延迟执行

  2.2 筛选:where

  也许最常用的查询操作是应用布尔表达式形式的筛选器。此筛选器使查询只返回那些表达式结果为 true 的元素。使用 where 子句生成结果。实际上,筛选器指定从源序列中排除哪些元素。

必威 23必威 24

1     var queryLondonCustomers = from cust in customers
2                                   where cust.City = "London"
3                                     select cust;

只返回地址位于伦敦的 customers。

  您可以使用熟悉的 C# 逻辑 AND(&&)和 OR(||) 运算符来根据需要在 where 子句中应用任意数量的筛选表达式。 

必威 25必威 26

where cust.City = "London" && cust.Name = "Devon"

若要只返回位于“伦敦”和姓名为“Devon”的客户

必威 27必威 28

where cust.City = "London" || cust.Name = "Paris"

若要返回位于伦敦或巴黎的客户

 

  2.2 筛选:where

  也许最常用的查询操作是应用布尔表达式形式的筛选器。此筛选器使查询只返回那些表达式结果为 true 的元素。使用 where 子句生成结果。实际上,筛选器指定从源序列中排除哪些元素。

必威 291 var queryLondonCustomers = from cust in customers 2        where cust.City = "London" 3       select cust; 只返回地址位于伦敦的 customers。

  您可以使用熟悉的 C# 逻辑 AND(&&)和 OR(||) 运算符来根据需要在 where 子句中应用任意数量的筛选表达式。 

必威 30where cust.City = "London" && cust.Name = "Devon" 若要只返回位于“伦敦”和姓名为“Devon”的客户 必威 31where cust.City = "London" || cust.Name = "Paris" 若要返回位于伦敦或巴黎的客户

 

     查询变量本身只是存储查询命令。实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。此概念称为“延迟执行”

  2.3 排序:orderby

  通常可以很方便地将返回的数据进行排序。orderby 子句将使返回的序列中的元素按照被排序的类型的默认比较器进行排序。

必威 32必威 33

1     var queryLondonCustomers = from cust in customers
2                                where cust.City = "London"
3                                orderby cust.Name descending 
4                                select cust;

按 Name 属性对结果进行排序

  因为 Name 是一个字符串,所以默认比较器执行从 A 到 Z 的字母排序。若要按相反顺序(从 Z 到 A)对结果进行排序,请使用 orderby…descending 子句。

 

  2.3 排序:orderby

  通常可以很方便地将返回的数据进行排序。orderby 子句将使返回的序列中的元素按照被排序的类型的默认比较器进行排序。

必威 341 var queryLondonCustomers = from cust in customers 2 where cust.City = "London" 3 orderby cust.Name descending 4 select cust; 按 Name 属性对结果进行排序

  因为 Name 是一个字符串,所以默认比较器执行从 A 到 Z 的字母排序。若要按相反顺序(从 Z 到 A)对结果进行排序,请使用 orderby…descending 子句。

 

foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}

  2.4 分组:group

  使用 group 子句,您可以按指定的键分组结果。

必威 35必威 36

 1     var queryLondonCustomers = from cust in customers
 2                     group cust by cust.City;
 3 
 4     foreach (var queryLondonCustomer in queryLondonCustomers)
 5     {
 6        Console.WriteLine(queryLondonCustomer.Key);
 7        foreach (var cust in queryLondonCustomer)
 8        {
 9           Console.WriteLine(cust.Name);
10        }
11     }

您可以指定结果应按 City 分组,以便位于伦敦或巴黎的所有客户位于各自组中。

  在本例中,cust.City 是键。

  在使用 group 子句结束查询时,结果采用列表的列表形式。列表中的每个元素是一个具有 Key 成员及根据该键分组的元素列表的对象。在循环访问生成组序列的查询时,您必须使用嵌套的 foreach 循环。外部循环用于循环访问每个组,内部循环用于循环访问每个组的成员。  

  如果您必须引用组操作的结果,可以使用 into 关键字来创建可进一步查询的标识符。

必威 37必威 38

1     //custQuery 是 IEnumable<IGrouping<string, Customer>> 类型
2     var custQuery = from cust in customers
3                     group cust by cust.City
4                     into custGroup
5                     where custGroup.Count() > 2
6                     orderby custGroup.Key
7                     select custGroup;

这里的查询只返回那些包含两个以上的客户的组。

 

  2.4 分组:group

  使用 group 子句,您可以按指定的键分组结果。

必威 39 1 var queryLondonCustomers = from cust in customers 2 group cust by cust.City; 3 4 foreach (var queryLondonCustomer in queryLondonCustomers) 5 { 6 Console.WriteLine(queryLondonCustomer.Key); 7 foreach (var cust in queryLondonCustomer) 8 { 9 Console.WriteLine(cust.Name); 10 } 11 } 您可以指定结果应按 City 分组,以便位于伦敦或巴黎的所有客户位于各自组中。

  在本例中,cust.City 是键。

  在使用 group 子句结束查询时,结果采用列表的列表形式。列表中的每个元素是一个具有 Key 成员及根据该键分组的元素列表的对象。在循环访问生成组序列的查询时,您必须使用嵌套的 foreach 循环。外部循环用于循环访问每个组,内部循环用于循环访问每个组的成员。  

  如果您必须引用组操作的结果,可以使用 into 关键字来创建可进一步查询的标识符。

必威 401 //custQuery 是 IEnumable<IGrouping<string, Customer>> 类型 2 var custQuery = from cust in customers 3 group cust by cust.City 4 into custGroup 5 where custGroup.Count() > 2 6 orderby custGroup.Key 7 select custGroup; 这里的查询只返回那些包含两个以上的客户的组。

 

      • 强制立即执行

  2.5 联接:join

  联接运算创建数据源中没有显式建模的序列之间的关联。例如,您可以执行联接来查找位于同一地点的所有客户和经销商。在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。  

必威 41必威 42

1     var innerJoinQuery = from cust in customers
2                        join dist in distributors on cust.City equals dist.City
3                        select new {CustomerName = cust.Name, DistributorName = dist.Name};

例如,您可以执行联接来查找位于同一地点的所有客户和经销商。

  在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。  

  在 LINQ 中,您不必像在 SQL 中那样频繁使用 join,因为 LINQ 中的外键在对象模型中表示为包含项集合的属性。

必威 43必威 44

    from order in Customer.Orders...

例如,Customer 对象包含 Order 对象的集合。不必执行联接,只需使用点表示法访问订单。

  

  2.5 联接:join

  联接运算创建数据源中没有显式建模的序列之间的关联。例如,您可以执行联接来查找位于同一地点的所有客户和经销商。在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。  

必威 451 var innerJoinQuery = from cust in customers 2   join dist in distributors on cust.City equals dist.City 3   select new {CustomerName = cust.Name, DistributorName = dist.Name}; 例如,您可以执行联接来查找位于同一地点的所有客户和经销商。

  在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。  

  在 LINQ 中,您不必像在 SQL 中那样频繁使用 join,因为 LINQ 中的外键在对象模型中表示为包含项集合的属性。

必威 46 from order in Customer.Orders... 例如,Customer 对象包含 Order 对象的集合。不必执行联接,只需使用点表示法访问订单。

  

     对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。 Count、Max、Average 和 First 就属于此类查询。由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。

  2.6 选择(投影):select

  select 子句生成查询结果并指定每个返回的元素的“形状”或类型。

  例如,您可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。当 select 子句生成除源元素副本以外的内容时,该操作称为“投影”。

 

  2.6 选择(投影):select

  select 子句生成查询结果并指定每个返回的元素的“形状”或类型。

  例如,您可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。当 select 子句生成除源元素副本以外的内容时,该操作称为“投影”。

 

var evenNumQuery = 
    from num in numbers
    where (num % 2) == 0
    select num;
int evenNumCount = evenNumQuery.Count();

三、使用 LINQ 进行数据转换

  语言集成查询 (LINQ) 不仅可用于检索数据,而且还是一个功能强大的数据转换工具。通过使用 LINQ 查询,您可以将源序列用作输入,并采用多种方式修改它以创建新的输出序列。您可以通过排序和分组来修改该序列,而不必修改元素本身。但是,LINQ 查询的最强大的功能是能够创建新类型。这一功能在 select 子句中实现。 例如,可以执行下列任务:  

  

三、使用 LINQ 进行数据转换

  语言集成查询 (LINQ) 不仅可用于检索数据,而且还是一个功能强大的数据转换工具。通过使用 LINQ 查询,您可以将源序列用作输入,并采用多种方式修改它以创建新的输出序列。您可以通过排序和分组来修改该序列,而不必修改元素本身。但是,LINQ 查询的最强大的功能是能够创建新类型。这一功能在 select 子句中实现。 例如,可以执行下列任务:  

  

     若要强制立即执行任意查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法。

  3.1 将多个输入联接到一个输出序列

必威 47必威 48

 1     class Student
 2     {
 3         public string Name { get; set; }
 4 
 5         public int Age { get; set; }
 6 
 7         public string City { get; set; }
 8 
 9         public List<int> Scores { get; set; }
10     }
11 
12     class Teacher
13     {
14         public int Id { get; set; }
15 
16         public string Name { get; set; }
17 
18         public int Age { get; set; }
19 
20         public string City { get; set; }
21 
22     }

学生和老师两个类

必威 49必威 50

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             //创建第一个数据源
 6             var students = new List<Student>()
 7             {
 8                 new Student()
 9                 {
10                     Age = 23,
11                     City = "广州",
12                     Name = "小C",
13                     Scores = new List<int>(){85,88,83,97}
14                 },
15                 new Student()
16                 {
17                     Age = 18,
18                     City = "广西",
19                     Name = "小明",
20                     Scores = new List<int>(){86,78,85,90}
21                 },
22                 new Student()
23                 {
24                     Age = 33,
25                     City = "梦里",
26                     Name = "小叁",
27                     Scores = new List<int>(){86,68,73,97}
28                 }
29             };
30 
31             //创建第二个数据源
32             var teachers = new List<Teacher>()
33             {
34                 new Teacher()
35                 {
36                     Age = 35,
37                     City = "梦里",
38                     Name = "啵哆"
39                 },
40                 new Teacher()
41                 {
42                     Age = 28,
43                     City = "云南",
44                     Name = "小红"
45                 },
46                 new Teacher()
47                 {
48                     Age = 38,
49                     City = "河南",
50                     Name = "丽丽"
51                 }
52             };
53 
54             //创建查询
55             var peopleInDreams = (from student in students
56                             where student.City == "梦里"
57                             select student.Name)
58                             .Concat(from teacher in teachers
59                                     where teacher.City == "梦里"
60                                     select teacher.Name);
61 
62             //执行查询
63             foreach (var person in peopleInDreams)
64             {
65                 Console.WriteLine(person);
66             }
67 
68             Console.Read();
69         }
70     }

控制台输出代码。   

 

  3.1 将多个输入联接到一个输出序列

必威 51 1 class Student 2 { 3 public string Name { get; set; } 4 5 public int Age { get; set; } 6 7 public string City { get; set; } 8 9 public List<int> Scores { get; set; } 10 } 11 12 class Teacher 13 { 14 public int Id { get; set; } 15 16 public string Name { get; set; } 17 18 public int Age { get; set; } 19 20 public string City { get; set; } 21 22 } 学生和老师两个类 必威 52 1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 //创建第一个数据源 6 var students = new List<Student>() 7 { 8 new Student() 9 { 10 Age = 23, 11 City = "广州", 12 Name = "小C", 13 Scores = new List<int>(){85,88,83,97} 14 }, 15 new Student() 16 { 17 Age = 18, 18 City = "广西", 19 Name = "小明", 20 Scores = new List<int>(){86,78,85,90} 21 }, 22 new Student() 23 { 24 Age = 33, 25 City = "梦里", 26 Name = "小叁", 27 Scores = new List<int>(){86,68,73,97} 28 } 29 }; 30 31 //创建第二个数据源 32 var teachers = new List<Teacher>() 33 { 34 new Teacher() 35 { 36 Age = 35, 37 City = "梦里", 38 Name = "啵哆" 39 }, 40 new Teacher() 41 { 42 Age = 28, 43 City = "云南", 44 Name = "小红" 45 }, 46 new Teacher() 47 { 48 Age = 38, 49 City = "河南", 50 Name = "丽丽" 51 } 52 }; 53 54 //创建查询 55 var peopleInDreams = (from student in students 56 where student.City == "梦里" 57 select student.Name) 58 .Concat(from teacher in teachers 59 where teacher.City == "梦里" 60 select teacher.Name); 61 62 //执行查询 63 foreach (var person in peopleInDreams) 64 { 65 Console.WriteLine(person); 66 } 67 68 Console.Read(); 69 } 70 } 控制台输出代码。

必威 53

 

List<int> numQuery2 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToList();

  3.2 选择各个源元素的子集

  1. 若要只选择源元素的一个成员,请使用点运算。

1     var query = from cust in Customers
2                     select cust.City;

  

  2. 若要创建包含源元素的多个属性的元素,可以使用具有命名对象或匿名类型的对象初始值设定项。

1     var query = from cust in Customer
2                    select new {Name = cust.Name, City = cust.City};

 

  3.2 选择各个源元素的子集

  1. 若要只选择源元素的一个成员,请使用点运算。

1     var query = from cust in Customers
2                     select cust.City;

  

  2. 若要创建包含源元素的多个属性的元素,可以使用具有命名对象或匿名类型的对象初始值设定项。

1     var query = from cust in Customer
2                    select new {Name = cust.Name, City = cust.City};

 

  • 支持 LINQ 的功能
    • 查询表达式

  3.3 将内存中的对象转换为 XML

必威 54必威 55

 1             //创建数据源
 2             var students = new List<Student>()
 3             {
 4                 new Student()
 5                 {
 6                     Age = 18,
 7                     Name = "小A",
 8                     Scores = new List<int>() {88,85,74,66 }
 9                 },
10                 new Student()
11                 {
12                     Age = 35,
13                     Name = "小B",
14                     Scores = new List<int>() {88,85,74,66 }
15                 },
16                 new Student()
17                 {
18                     Age = 28,
19                     Name = "小啥",
20                     Scores = new List<int>() {88,85,74,66 }
21                 }
22             };
23 
24             //创建查询
25             var studentsToXml = new XElement("Root",
26                 from student in students
27                 let x = $"{student.Scores[0]},{student.Scores[1]},{student.Scores[2]},{student.Scores[3]}"
28                 select new XElement("student",
29                 new XElement("Name", student.Name),
30                 new XElement("Age", student.Age),
31                 new XElement("Scores", x))
32             );
33 
34             //执行查询
35             Console.WriteLine(studentsToXml);

View Code

必威 56

 

  3.3 将内存中的对象转换为 XML

必威 57 1 //创建数据源 2 var students = new List<Student>() 3 { 4 new Student() 5 { 6 Age = 18, 7 Name = "小A", 8 Scores = new List<int>() {88,85,74,66 } 9 }, 10 new Student() 11 { 12 Age = 35, 13 Name = "小B", 14 Scores = new List<int>() {88,85,74,66 } 15 }, 16 new Student() 17 { 18 Age = 28, 19 Name = "小啥", 20 Scores = new List<int>() {88,85,74,66 } 21 } 22 }; 23 24 //创建查询 25 var studentsToXml = new XElement("Root", 26 from student in students 27 let x = $"{student.Scores[0]},{student.Scores[1]},{student.Scores[2]},{student.Scores[3]}" 28 select new XElement("student", 29 new XElement("Name", student.Name), 30 new XElement("Age", student.Age), 31 new XElement("Scores", x)) 32 ); 33 34 //执行查询 35 Console.WriteLine(studentsToXml); View Code

必威 58

 

     查询表达式使用类似于 SQL 或 XQuery 的声明性语法来查询 IEnumerable 集合。在编译时,查询语法转换为对 LINQ 提供程序的标准查询运算符扩展方法实现的方法调用。应用程序通过使用 using 指令指定适当的命名空间来控制范围内的标准查询运算符。下面的查询表达式获取一个字符串数组,按字符串中的第一个字符对字符串进行分组,然后对各组进行排序。

  3.4 对源元素执行操作

  输出序列可能不包含源序列的任何元素或元素属性。输出可能是通过将源元素用作输入参数计算出的值的序列。

必威 59必威 60

 1             //数据源
 2             double[] radii = {1, 2, 3};
 3 
 4             //创建查询
 5             var query = from radius in radii
 6                 select $"{radius * radius * 3.14}";
 7 
 8             //执行查询
 9             foreach (var i in query)
10             {
11                 Console.WriteLine(i);
12             }

View Code

必威 61

   【备注】$"{radius * radius * 3.14}" 相当于 string.Format("{0}",radius * radius * 3.14),这里采用的是 C# 6.0 的语法。

 

  3.4 对源元素执行操作

  输出序列可能不包含源序列的任何元素或元素属性。输出可能是通过将源元素用作输入参数计算出的值的序列。

必威 62 1 //数据源 2 double[] radii = {1, 2, 3}; 3 4 //创建查询 5 var query = from radius in radii 6 select $"{radius * radius * 3.14}"; 7 8 //执行查询 9 foreach (var i in query) 10 { 11 Console.WriteLine(i); 12 } View Code

必威 63

 

var query = from str in stringArray
            group str by str[0] into stringGroup
            orderby stringGroup.Key
            select stringGroup;

四、LINQ 查询操作的类型关系

  LINQ 查询操作在数据源、查询本身及查询执行中是强类型的。查询中变量的类型必须与数据源中元素的类型和 foreach 语句中迭代变量的类型兼容。强类型可以保证在编译时捕获类型错误,以便及时改正。

 

四、LINQ 查询操作的类型关系

  LINQ 查询操作在数据源、查询本身及查询执行中是强类型的。查询中变量的类型必须与数据源中元素的类型和 foreach 语句中迭代变量的类型兼容。此强类型保证在编译时捕获类型错误,以便可以在用户遇到这些错误之前更正它们。

 

    • 隐式类型化变量

  4.1 不转换源数据的查询

  下图演示不对数据执行转换的 LINQ to Objects 查询操作。源包含一个字符串序列,查询输出也是一个字符串序列。 

必威 64

  ①数据源的类型参数决定范围变量的类型。

  ②选择的对象的类型决定查询变量的类型。此处的 name 为一个字符串。因此,查询变量是一个 IEnumerable<字符串>。  

  ③在 foreach 语句中循环访问查询变量。因为查询变量是一个字符串序列,所以迭代变量也是一个字符串。  

 

  4.1 不转换源数据的查询

  下图演示不对数据执行转换的 LINQ to Objects 查询操作。源包含一个字符串序列,查询输出也是一个字符串序列。 

必威 65

  (1)数据源的类型参数决定范围变量的类型。

  (2)选择的对象的类型决定查询变量的类型。此处的 name 为一个字符串。因此,查询变量是一个 IEnumerable<字符串>。  

  (3)在 foreach 语句中循环访问查询变量。因为查询变量是一个字符串序列,所以迭代变量也是一个字符串。  

 

     不必在声明并初始化变量时显式指定类型,您可以使用 var 修饰符来指示编译器推断并分配类型,声明为 var 的变量与显式指定其类型的变量一样都是强类型。通过使用 var,可以创建匿名类型,但它可用于任何局部变量。也可以使用隐式类型声明数组。

  4.2 转换源数据的查询

  下图演示对数据执行简单转换的 LINQ to SQL 查询操作。查询将一个 Customer 对象序列用作输入,并只选择结果中的 Name 属性。因为 Name 是一个字符串,所以查询生成一个字符串序列作为输出。  

必威 66

  ①数据源的类型参数决定范围变量的类型。

  ②select 语句返回 Name 属性,而非完整的 Customer 对象。因为 Name 是一个字符串,所以 custNameQuery 的类型参数是 string,而非Customer。  

  ③因为 custNameQuery 是一个字符串序列,所以 foreach 循环的迭代变量也必须是 string

 

  下图演示另一种转换。select 语句返回只捕获原始 Customer 对象的两个成员的匿名类型。

必威 67

  ①数据源的类型参数始终为查询中的范围变量的类型。

  ②因为 select 语句生成匿名类型,所以必须使用 var 隐式类型化查询变量。

  ③因为查询变量的类型是隐式的,所以 foreach 循环中的迭代变量也必须是隐式的。

 

  4.2 转换源数据的查询

  下图演示对数据执行简单转换的 LINQ to SQL 查询操作。查询将一个 Customer 对象序列用作输入,并只选择结果中的 Name 属性。因为 Name 是一个字符串,所以查询生成一个字符串序列作为输出。  

必威 68

  (1)数据源的类型参数决定范围变量的类型。

  (2)select 语句返回 Name 属性,而非完整的 Customer 对象。因为 Name 是一个字符串,所以 custNameQuery 的类型参数是 string,而非Customer。  

  (3)因为 custNameQuery 是一个字符串序列,所以 foreach 循环的迭代变量也必须是 string

 

  下图演示另一种转换。select 语句返回只捕获原始 Customer 对象的两个成员的匿名类型。

必威 69

  (1)数据源的类型参数始终为查询中的范围变量的类型。

  (2)因为 select 语句生成匿名类型,所以必须使用 var 隐式类型化查询变量。

  (3)因为查询变量的类型是隐式的,所以 foreach 循环中的迭代变量也必须是隐式的。

 

var number = 5;
var name = "Virginia";
var query = from str in stringArray
            where str[0] == 'm'
            select str;

  4.3 让编译器推断类型信息

  您也可以使用关键字 var,可用于查询操作中的任何局部变量。但是,编译器为查询操作中的各个变量提供强类型。  

必威 70

 

  4.3 让编译器推断类型信息

  您也可以选择让编译器为您执行全部工作。关键字 var 可用于查询操作中的任何局部变量。但是,编译器为查询操作中的各个变量提供强类型。  

必威 71

 

    • 对象和集合初始值设定项

五、LINQ 中的查询语法和方法语法

  我们编写的 LINQ 查询语法,在编译代码时,CLR 会将查询语法转换为方法语法。这些方法调用标准查询运算符的名称类似 WhereSelectGroupByJoinMax和 Average,我们也是可以直接使用这些方法语法的。  

  查询语法和方法语法语义相同,但是,许多人员发现查询语法更简单、更易于阅读。某些查询必须表示为方法调用。例如,必须使用方法调用表示检索元素的数量与指定的条件的查询。还必须使用方法需要检索元素的最大值在源序列的查询。System.Linq 命名空间中的标准查询运算符的参考文档通常使用方法语法。

 

五、LINQ 中的查询语法和方法语法

  在表示语言集成查询 (LINQ) 使用 LINQ 性查询语法,文档中的多数查询编写。但是,编译代码时,必须将查询语法转换为方法,这就需要 .NET 公共语言运行时 (CLR)。这些方法调用标准查询运算符的名称类似 WhereSelectGroupByJoinMax和 Average。可以调用这些方法直接使用方法语法而不是查询语法。  

  查询语法和方法语法语义相同,但是,许多人员发现查询语法更简单、更易于阅读。某些查询必须表示为方法调用。例如,必须使用方法调用表示检索元素的数量与指定的条件的查询。还必须使用方法需要检索元素的最大值在源序列的查询。System.Linq 命名空间中的标准查询运算符的参考文档通常使用方法语法。

 

     通过对象和集合初始值设定项,初始化对象时无需为对象显式调用构造函数。初始值设定项通常用在将源数据投影到新数据类型的查询表达式中。假定一个类名为 Customer,具有公共 Name 和 Phone 属性,可以按下列代码中所示使用对象初始值设定项:

  5.1 标准查询运算符扩展方法

必威 72必威 73

 1         static void Main(string[] args)
 2         {
 3             var nums = new int[4] { 1, 2, 3, 4 };
 4             
 5             //创建查询表达式
 6             var qureyNums = from n in nums
 7                             where n % 2 == 0
 8                             orderby n descending
 9                             select n;
10 
11             Console.WriteLine("qureyNums:");
12             foreach (var n in qureyNums)
13             {
14                 Console.WriteLine(n);
15             }
16     
17             //使用方法进行查询
18             var queryNums2 = nums.Where(n => n % 2 == 0).OrderByDescending(n => n);
19 
20             Console.WriteLine("qureyNums2:");
21             foreach (var n in queryNums2)
22             {
23                 Console.WriteLine(n);
24             }
25 
26             Console.Read();
27         }

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

必威 74

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

  若要了解基于方法的查询,让我们进一步地分析它。注意,在表达式的右侧,where 子句现在表示为对 numbers 对象的实例方法,在您重新调用该对象时其类型为 IEnumerable<int>。如果您熟悉泛型 IEnumerable<T> 接口,那么您就会了解,它不具有 Where 方法。但是,如果您在 Visual Studio IDE 中调用 IntelliSense 完成列表,那么您不仅将看到 Where 方法,而且还会看到许多其他方法,如 SelectSelectManyJoin 和Orderby。下面是所有标准查询运算符。 

必威 75

  尽管看起来 IEnumerable<T> 似乎已被重新定义以包括这些附加方法,但事实上并非如此。这些标准查询运算符都是作为“扩展方法”实现的。

 

  5.1 标准查询运算符扩展方法

必威 76 1 static void Main(string[] args) 2 { 3 var nums = new int[4] { 1, 2, 3, 4 }; 4 5 //创建查询表达式 6 var qureyNums = from n in nums 7 where n % 2 == 0 8 orderby n descending 9 select n; 10 11 Console.WriteLine("qureyNums:"); 12 foreach (var n in qureyNums) 13 { 14 Console.WriteLine(n); 15 } 16 17 //使用方法进行查询 18 var queryNums2 = nums.Where(n => n % 2 == 0).OrderByDescending(n => n); 19 20 Console.WriteLine("qureyNums2:"); 21 foreach (var n in queryNums2) 22 { 23 Console.WriteLine(n); 24 } 25 26 Console.Read(); 27 } 下面的示例演示简单的查询表达式和编写为基于方法的查询的语义上等效的查询。

必威 77

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

  若要了解基于方法的查询,让我们进一步地分析它。注意,在表达式的右侧,where 子句现在表示为对 numbers 对象的实例方法,在您重新调用该对象时其类型为 IEnumerable<int>。如果您熟悉泛型 IEnumerable<T> 接口,那么您就会了解,它不具有 Where 方法。但是,如果您在 Visual Studio IDE 中调用 IntelliSense 完成列表,那么您不仅将看到 Where 方法,而且还会看到许多其他方法,如 SelectSelectManyJoin 和Orderby。下面是所有标准查询运算符。 

必威 78

  尽管看起来 IEnumerable<T> 似乎已被重新定义以包括这些附加方法,但事实上并非如此。这些标准查询运算符都是作为“扩展方法”实现的。

 

Customer cust = new Customer { Name = "Mike", Phone = "555-1212" };

  5.2 Lambda 表达式

  在前面的示例中,通知该条件表达式 (num % 2 == 0) 是作为内联参数。Where 方法:Where(num => num % 2 == 0) 此内联表达式称为 lambda 表达式。将代码编写为匿名方法或泛型委托或表达式树是一种便捷的方法,否则编写起来就要麻烦得多。=> 是 lambda 运算符,可读为“goes to”。运算符左侧的 num 是输入变量,与查询表达式中的 num 相对应。编译器可推断 num 的类型,因为它了解 numbers 是泛型 IEnumerable<T> 类型。lambda 表达式与查询语法中的表达式或任何其他 C# 表达式或语句中的表达式相同;它可以包括方法调用和其他复杂逻辑。“返回值”就是表达式结果。  

 

  5.2 Lambda 表达式

  在前面的示例中,通知该条件表达式 (num % 2 == 0) 是作为内联参数。Where 方法:Where(num => num % 2 == 0) 此内联表达式称为 lambda 表达式。将代码编写为匿名方法或泛型委托或表达式树是一种便捷的方法,否则编写起来就要麻烦得多。=> 是 lambda 运算符,可读为“goes to”。运算符左侧的 num 是输入变量,与查询表达式中的 num 相对应。编译器可推断 num 的类型,因为它了解 numbers 是泛型 IEnumerable<T> 类型。lambda 表达式与查询语法中的表达式或任何其他 C# 表达式或语句中的表达式相同;它可以包括方法调用和其他复杂逻辑。“返回值”就是表达式结果。  

 

    • 匿名类型

  5.3 查询的组合性

  在上面的代码示例中,请注意 OrderBy 方法是通过在对 Where 的调用中使用点运算符来调用的。Where 生成筛选序列,然后 Orderby 通过对该序列排序来对它进行操作。因为查询会返回 IEnumerable,所以您可通过将方法调用链接在一起,在方法语法中将这些查询组合起来。这就是在您通过使用查询语法编写查询时编译器在后台所执行的操作。并且由于查询变量不存储查询的结果,因此您可以随时修改它或将它用作新查询的基础,即使在执行它后。

 

  5.3 查询的组合性

  在上面的代码示例中,请注意 OrderBy 方法是通过在对 Where必威, 的调用中使用点运算符来调用的。Where 生成筛选序列,然后 Orderby 通过对该序列排序来对它进行操作。因为查询会返回 IEnumerable,所以您可通过将方法调用链接在一起,在方法语法中将这些查询组合起来。这就是在您通过使用查询语法编写查询时编译器在后台所执行的操作。并且由于查询变量不存储查询的结果,因此您可以随时修改它或将它用作新查询的基础,即使在执行它后。

 

本文首联:

 

--待整理完成后重新发布到首页--

  

] 开始使用 LINQ, 开始使用 LINQ 在此之前曾发表过三篇关于 LINQ 的随笔: 进阶:《LINQ 标准查询操作概述》 (强烈推荐) 技巧:《Linq...

     匿名类型由编译器构建,且类型名称只可用于编译器。匿名类型提供了一种在查询结果中临时分组一组属性的方便方法,无需定义单独的命名类型。使用新的表达式和对象初始值设定项初始化匿名类型。

传送门

  入门:《走进 LINQ 的世界》

  进阶:《LINQ 标准查询操作概述》(强烈推荐)

  技巧:《Linq To Objects - 如何操作字符串》 和 《Linq To Objects - 如何操作文件目录》

 

 


本文首联:

【参考】 等

【来源】本文引用部分微软官方文档的图片

 

 

  

select new {name = cust.Name, phone = cust.Phone};
    • 扩展方法

     扩展方法是一种可与类型关联的静态方法,因此可以像实例方法那样对类型调用它。实际上,此功能使您能够将新方法“添加”到现有类型,而不会实际修改它们。标准查询运算符是一组扩展方法,它们为实现 IEnumerable<T> 的任何类型提供 LINQ 查询功能。

    • Lambda 表达式

     Lambda 表达式是一种内联函数,该函数使用 => 运算符将输入参数与函数体分离,并且可以在编译时转换为委托或表达式树。在 LINQ 编程中,在您对标准查询运算符进行直接方法调用时,会遇到 lambda 表达式。

    • 自动实现的属性

     通过自动实现的属性,可以更简明地声明属性。当您如下面的示例中所示声明属性时,编译器将创建一个私有的匿名支持字段,该字段只能通过属性 getter 和 setter 进行访问。

public string Name {get; set;}
  • LINQ 泛型
    •  IEnumerable<T> 变量

     LINQ 查询变量类型化为 IEnumerable<T> 或派生类型,如 IQueryable<T>。当您看到类型化为 IEnumerable<Customer> 的查询变量时,这只意味着在执行该查询时,该查询将生成包含零个或多个 Customer 对象的序列。

IEnumerable<Customer> 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,应意识到这可能使您的代码更难以让别人理解。

var customerQuery2 = 
    from cust in customers
    where cust.City == "London"
    select cust;
foreach(var customer in customerQuery2)
{
    Console.WriteLine(customer.LastName + ", " + customer.FirstName);
}
  • LINQ to Objects

     术语“LINQ to Objects”是指直接对任意 IEnumerable 或 IEnumerable<T> 集合使用 LINQ 查询,无需使用中间 LINQ 提供程序或 API,如 LINQ to SQL 或 LINQ to XML。 可以使用 LINQ 来查询任何可枚举的集合,如 List<T>、Array 或 Dictionary<TKey, TValue>。 该集合可以是用户定义的集合,也可以是 .NET Framework API 返回的集合。

     从根本上说,LINQ to Objects 表示一种新的处理集合的方法。 采用旧方法,您必须编写指定如何从集合检索数据的复杂的 foreach 循环。 而采用 LINQ 方法,您只需编写描述要检索的内容的声明性代码。

     另外,与传统的 foreach 循环相比,LINQ 查询具有三大优势:

    • 它们更简明、更易读,尤其在筛选多个条件时。
    • 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能。
    • 无需修改或只需做很小的修改即可将它们移植到其他数据源。

本文由必威发布于编程,转载请注明出处:开始使用