[C#] 走进 LINQ 的世界

走进 LINQ 的世界

  以前曾发表过三篇有关 LINQ 的小说:

    进阶:《LINQ
标准查询操作概述》(猛烈推荐卡塔尔

    技巧:《Linq To Objects –
怎么着操作字符串》 和
《Linq To Objects –
怎么着操作文件目录》

  今后,自个儿准备再整合治理生机勃勃篇有关 LINQ 入门的小说,也是活泼的啊。

 

目录

  • LINQ 简介
  • 介绍 LINQ
    查询
  • LINQ
    基本查询操作
  • 动用 LINQ
    举办数据转变
  • LINQ
    查询操作的种类涉及
  • LINQ
    中的查询语法和艺术语法

 

LINQ 简介

  语言集成查询 (LINQ) 是 Visual Studio 二零零六 和 .NET Framework 3.5
版中引进的风度翩翩项改进意义。

  守旧上,针对数据的询问都以以轻巧的字符串表示,而并未有编写翻译时类型检查或
AMDliSense
帮助。其余,您还非得针对以下各样数据源学习大器晚成种差异的查询语言:SQL
数据库、XML 文书档案、种种 Web 服务等等。 通过LINQ,
您能够运用语言关键字和熟知的演算符针对强类型化对象集结编写查询。

永利皇宫463手机版 1

  

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

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

 

一、介绍 LINQ 查询

  查询是生龙活虎种从数据源检索数据的表达式。随着岁月的推移,大家曾经为各个数据源开采了不一致的语言;举例,用于关全面据库的
SQL 和用来 XML 的
XQuery。由此,开采人士必须要针对他们必需帮助的各种数据源或数额格式而上学新的询问语言。LINQ
通过提供生机勃勃种跨数据源和数目格式使用数据的相符模型,简化了那风流浪漫情景。在
LINQ 查询中,始终会用到对象。能够选拔雷同的编码方式来询问和改动 XML
文书档案、SQL 数据库、ADO.NET 数据集、.NET 集结中的数据以至对其有 LINQ
提供程序可用的别的其余格式的数据。  

 

  1.1 查询操作的几个部分

  操作三部曲:①取多少源 ②创办查询 ③施行查询

永利皇宫463手机版 2永利皇宫463手机版 3

 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

永利皇宫463手机版 4

 

   下图显示了全部的询问操作。在 LINQ
中,查询的进行与查询本身天壤之别;换句话说,查询自个儿指的是只成立查询变量,不检索任何数据。

永利皇宫463手机版 5

  

  1.2 数据源

  在上一个演示中,由于数据源是数组,因而它隐式接济泛型 IEnumerable<T> 接口。支持 IEnumerable<T> 或派生接口(如泛型 IQueryable<T>卡塔 尔(英语:State of Qatar)的类外号为可查询类型。  

  可查询类型没有必要张开改革或非常管理就足以用作 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 在运作时管理与数据库的通信。

永利皇宫463手机版 6永利皇宫463手机版 7

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.3 查询

  查询钦命要从数量源中检索的新闻。
查询还是能钦定在回去这个新闻以前怎么着对其张开排序、分组和结构化。
查询存款和储蓄在查询变量中,并用查询表明式进行带头化。

  以前的身体力行中的查询是从整数数组中回到全体的偶数。
该查询表达式包括多个子句:fromwhere 和 select。(假诺你熟习SQL,您会小心到这个子句的逐一与 SQL
中的顺序相反。卡塔 尔(阿拉伯语:قطر‎from 子句内定数据源,where 子句内定应用筛选器,select 子句钦赐重临的成分的品类。
前段时间亟需在意的是,在 LINQ 中,查询变量本人不施行其余操作并且不回来任何数据。
它只是存款和储蓄在后来有些时刻奉行查询时为变化结果而供给的音讯。

 

  1.4 查询实行

  1.延缓实施

    如前所述,查询变量自个儿只是存款和储蓄查询命令。  实际的询问实行会延迟到在 foreach 语句中循环访谈查询变量时产生。
此概念称为“延迟实践”。

  2.威胁立时奉行

    对风流洒脱多元源成分推行聚合函数的询问必须首先循环访谈那个成分。CountMaxAverage 和 First 就归于此类查询。由于查询本人必需接纳 foreach 以便回到结果,由此这几个查询在推行时不采取显式 foreach 语句。其它还要注意,那个项目标询问再次来到单个值,实际不是 IEnumerable 集合。 

永利皇宫463手机版 8永利皇宫463手机版 9

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

永利皇宫463手机版 10

 

  若要强制立刻进行大肆查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法。

永利皇宫463手机版 11永利皇宫463手机版 12

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 查询操作

  2.1 获取数据源:from

  在 LINQ
查询中,第一步是点名数据源。像在大相当多编制程序语言中平等,必需先注脚变量,才干采用它。在
LINQ 查询中,最初使用 from 子句的指标是引入数据源和约束变量。

永利皇宫463手机版 13永利皇宫463手机版 14

1     //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 子句生成结果。实际上,筛选器内定从源系列中消释哪些要素。

永利皇宫463手机版 15永利皇宫463手机版 16

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

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

  您可以利用深谙的 C#
逻辑 AND(&&)和 OR(||) 运算符来依据需求在 where 子句中接纳大肆数量的筛选表明式。 

永利皇宫463手机版 17永利皇宫463手机版 18

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

若要只回去位于“London”和人名叫“Devon”的客商

永利皇宫463手机版 19永利皇宫463手机版 20

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

若要再次回到位于London或法国巴黎的顾客

 

  2.3 排序:orderby

  经常能够很有益于地将回来的数额开展排序。orderby 子句将使重返的类别中的成分遵照被排序的类型的默许相比较器实行排序。

永利皇宫463手机版 21永利皇宫463手机版 22

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.4 分组:group

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

永利皇宫463手机版 23永利皇宫463手机版 24

 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
分组,以便位于London或法国巴黎的具有客商位于各自己创设中。

  在本例中,cust.City 是键。

  在使用 group 子句结束查询时,结果使用列表的列表形式。列表中的每一种成分是三个持有 Key 成员及依据该键分组的因素列表的对象。在循环访谈生成组体系的询问时,您必得采用嵌套的 foreach 循环。外界循环用于循环访谈各类组,内部循环用于循环访谈种种组的分子。
 

  假让你必需援引组操作的结果,能够采取 into 关键字来创设可进一步查询的标记符。

永利皇宫463手机版 25永利皇宫463手机版 26

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.5 联接:join

  联接运算创造数量源中未有显式建立模型的队列之间的关系。举例,您能够实行联接来找出位于同生龙活虎地方的具备顾客和中间商。在
LINQ 中,join 子句始终照准对象会集而非直接指向数据库表运营。  

永利皇宫463手机版 27永利皇宫463手机版 28

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
中的外键在对象模型中表示为带有项会集的性情。

永利皇宫463手机版 29永利皇宫463手机版 30

    from order in Customer.Orders...

举个例子,Customer 对象包含 Order
对象的集纳。不必实施联接,只需使用点表示法访谈订单。

  

  2.6 选择(投影):select

  select 子句生成查询结果并钦赐每一个重返的因素的“形状”或项目。

  举例,您能够钦点结果包涵的是百分之百 Customer 对象、仅一个分子、成员的子集,照旧某些基于计算或新对象创立的通通两样的结果类型。当 select 子句生成除源成分别本以外的从头到尾的经过时,该操作称为“投影”。

 

三、使用 LINQ 实行数量调换

  语言集成查询 (LINQ)
不只有可用于检索数据,何况依然一个作用强盛的多寡转变工具。通过行使 LINQ
查询,您能够将源体系用作输入,并动用三种方法修正它以创办新的出口种类。您能够通过排序和分组来修正该种类,而不要改进成分本身。可是,LINQ
查询的最精锐的作用是能够成立新品类。那大器晚成成效在 select 子句中贯彻。 举个例子,能够实践下列任务:  

  

  3.1 将多少个输入联接到八个输出连串

永利皇宫463手机版 31永利皇宫463手机版 32

 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     }

学员和名师五个类

永利皇宫463手机版 33永利皇宫463手机版 34

 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.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.3 将内部存款和储蓄器中的目的调换为 XML

永利皇宫463手机版 35永利皇宫463手机版 36

 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);

永利皇宫463手机版,View Code

永利皇宫463手机版 37

 

  3.4 对源成分施行操作

  输出体系只怕不包罗源系列的其余因素或因素属性。输出只怕是经过将源成分用作输入参数总结出的值的系列。

永利皇宫463手机版 38永利皇宫463手机版 39

 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

永利皇宫463手机版 40

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

 

四、LINQ 查询操作的门类涉及

  LINQ
查询操作在数据源、查询自个儿及查询实行中是强类型的。查询中变量的类别必需与数据源相月素的连串和 foreach 语句中迭代变量的门类包容。强类型能够确定保证在编译时捕获类型错误,以便及时修正。

 

  4.1 不转换源数据的查询

  下图演示不对数据进行调换的 LINQ to Objects
查询操作。源满含八个字符串种类,查询输出也是三个字符串类别。 

永利皇宫463手机版 41

  ①数据源的花色参数决定限定变量的档案的次序。

  ②筛选的靶子的品类决定查询变量的类型。此处的 name 为一个字符串。因而,查询变量是一个 IEnumerable<字符串>。
 

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

 

  4.2 调换源数据的询问

  下图演示对数据施行轻松调换的 LINQ to
SQL 查询操作。查询将三个 Customer 对象系列用作输入,并只采纳结果中的 Name 属性。因为 Name 是三个字符串,所以查询生成二个字符串体系作为出口。  

永利皇宫463手机版 42

  ①数据源的门类参数决定限定变量的项目。

  ②select 语句重临 Name 属性,而非完整的 Customer 对象。因为 Name 是二个字符串,所以 custNameQuery 的种类参数是 string,而非Customer。
 

  ③因为 custNameQuery 是三个字符串连串,所以 foreach 循环的迭代变量也必需是 string

 

  下图演示另生龙活虎种转移。select 语句重临只捕获原始 Customer 对象的七个成员的无名类型。

永利皇宫463手机版 43

  ①数据源的项目参数始终为查询中的范围变量的品种。

  ②因为 select 语句生成无名类型,所以必需选择 var 隐式类型化查询变量。

  ③因为查询变量的项目是隐式的,所以 foreach 循环中的迭代变量也亟须是隐式的。

 

  4.3 让编写翻译器测度类型音讯

  您也能够采用首要字 var,可用于查询操作中的任何部分变量。可是,编写翻译器为查询操作中的各种变量提供强类型。  

永利皇宫463手机版 44

 

五、LINQ 中的查询语法和艺术语法

  大家编辑的 LINQ 查询语法,在编写翻译代码时,CL福特Explorer会将查询语法调换为方式语法。那个办法调用规范查询运算符的称呼近似 WhereSelectGroupByJoinMax和 Average,大家也是足以一贯利用那么些情势语法的。
 

  查询语法和办越南语葡萄牙语义相通,可是,超多个人口开采查询语法更简短、更便于阅读。有些查询必得代表为艺术调用。举例,必得采纳办法调用表示检索成分的数目与钦点的标准化的询问。还必需利用方法必要搜索成分的最大值在源体系的询问。System.Linq 命名空间中的标准查询运算符的参谋文书档案平常使用方土耳其语法。

 

  5.1 规范查询运算符扩大方法

永利皇宫463手机版 45永利皇宫463手机版 46

 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         }

下边包车型客车亲自过问演示简单的查询表明式和编辑为依靠方法的询问的语义上等效的询问。

永利皇宫463手机版 47

  多少个示范的出口是均等的。您可以见见二种样式的查询变量的门类是雷同的:IEnumerable<T>。
 

  若要精通基于方法的查询,让我们越发地解析它。注意,在表明式的左边,where 子句以后意味着为对 numbers 对象的实例方法,在你再度调用该指标时其种类为 IEnumerable<int>。要是你熟识泛型 IEnumerable<T> 接口,那么您就能够询问,它不享有 Where 方法。但是,若是您在
Visual Studio IDE 中调用 英特尔liSense
达成列表,那么你不仅仅将见到 Where 方法,并且还有或者会看出不知凡几别样办法,如 SelectSelectManyJoin 和Orderby。下边是装有正式查询运算符。 

永利皇宫463手机版 48

  固然看起来 IEnumerable<T> 如同已被再次定义以囊括这么些附加措施,但实际上并非那样。这么些专门的学业查询运算符都以当作“扩展方法”完成的。

 

  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,所以您可因而将艺术调用链接在一块,在艺术语法少校那几个查询组合起来。那正是在您通过利用查询语法编写查询时编写翻译器在后台所实行的操作。况且鉴于查询变量不存款和储蓄查询的结果,由此你能够每一天改善它或将它用作新查询的底蕴,即便在举办它后。

 

传送门

  入门:《走进 LINQ
的世界》

  进阶:《LINQ
标准查询操作概述》(刚强推荐卡塔 尔(英语:State of Qatar)

  技巧:《Linq To Objects –
怎样操作字符串》 和
《Linq To Objects –
怎样操作文件目录》

 

 


正文首联:

【参考】

【来源】本文援引部分微软官方文书档案的图形

 

 

  

发表评论

电子邮件地址不会被公开。 必填项已用*标注