关于LINQ的文章,网上有很多,所以这篇文章我主要是总结下我自己的学习心得。

首先需要先了解的相关技术

1.隐式类型、匿名类型、对象初始化器

1)隐式类型,使用var关键字创建,C#编译器会根据用于初始化局部变量的初始值推断出变量的数据类型。(不过我个人认为,能用具体类型的地方尽量不要用var关键字,因为这样会让你遗忘“被封装类库”方法的返回值类型--有损可读性)

隐式类型使用限制:

a) 隐式类型只能应用于方法或者属性内局部变量的声明,不能使用var来定义返回值、参数的类型或类型的数据成员。

b)使用var进行声明的局部变量必须赋初始值,并且不能以null作为初始值。

2) 匿名类型,只是一个继承了Object的、没有名称的类。C#编译器会在编译时自动生成名称唯一的类。

3) 对象初始化器,提供一种非常简洁的方式来创建对象和为对象的属性赋值。(相关还有“集合初始化器”)

由于C#强类型语言,即我们在声明变量时必须指定变量的具体类型。所以在创建匿名对象时,需要结合隐式类型、匿名类型、对象初始化器一起创建匿名对象。(避免类型转换)

示例:

var person = new { name = “heyuquan” , age = 24 }

由于C#强类型语言,即我们在声明变量时必须指定变量的具体类型。所以在创建匿名对象时,需要结合隐式类型、匿名类型、对象初始化器一起创建匿名对象。(避免类型转换)

2.Lambda表达式,Func委托

1)Lambda表达式只是用更简单的方式来书写匿名方法,从而彻底简化.NET委托类型的使用。

Lambda表达式在C#中的写法是“arg-list => expr-body”,“=>”符号左边为表达式的参数列表,右边则是表达式体(body)。参数列表可以包含0到多个参数,参数之间使用逗号分割。

2)Func委托

Func委托,是微软为我们预定义的常用委托,封装一个具有:零个或多个指定类型的输入参数并返回一个指定类型的结果值的方法。

示例:

  1. static void Main(string[] args)
  2. {
  3. // 委托函数
  4. Func<string, string, string> func1 = Hello;
  5. // 匿名方法
  6. Func<string, string, string> func2 =
  7. delegate(string a, string b)
  8. {
  9. return "欢迎光临我的博客" + Environment.NewLine + a + " " + b;
  10. };
  11. // Lambda表达式
  12. Func<string, string, string> func3 =
  13. (a, b) => { return "欢迎光临我的博客" + Environment.NewLine + a + " " + b; };
  14. // 调用Func委托
  15. string helloStr = func2("滴答的雨", @"http://www.cnblogs.com/heyuquan/");
  16. Console.WriteLine(helloStr);
  17. }
  18.  
  19. static string Hello(string a, string b)
  20. {
  21. return "欢迎光临我的博客" + Environment.NewLine + a + " " + b;
  22. }

3.扩展方法

1)扩展方法声明在静态类中,定义为一个静态方法,其第一个参数需要使用this关键字标识,指示它所扩展的类型。

2)扩展方法可以将方法写入最初没有提供该方法的类中。还可以把方法添加到实现某个接口的任何类中,这样多个类就可以使用相同的实现代码。(LINQ中,System.Linq.Queryable.cs和System.Linq.Enumerable.cs 正是对接口添加扩展方法)

3)扩展方法虽定义为一个静态方法,但其调用时不必提供定义静态方法的类名,只需引入对应的命名空间,访问方式同实例方法。

4)扩展方法不能访问它所扩展的类型的私有成员。

示例:

  1. public static IEnumerable<TSource> MyWhere<TSource>(
  2. this IEnumerable<TSource> source, Func<TSource, bool> predicate)
  3. {
  4. foreach (TSource item in source)
  5. {
  6. if (predicate(item))
  7. yield return item;
  8. }
  9. }

4.Yield迭代器,延迟计算

1)Yield迭代器

在上面定义的MyWhere扩展方法中,我们使用了yield迭代器。使我们不必“显示”实现IEnumerable或IEnumerator接口。只需要简单的使用yield 关键字,由 JIT 编译器帮我们编译成实现 IEnumerable或IEnumerator接口的对象(即:本质还是传统遍历,只是写法上非常简洁),就能使用foreach进行遍历。

2)延迟计算(Lazy evaluation)

a)定义:来源自函数式编程,在函数式编程里,将函数作为参数来传递,传递过程中不会执行函数内部耗时的计算,直到需要这个计算结果的时候才调用,这样就可以因为避免一些不必要的计算而改进性能。

b)Yield迭代器的延迟计算原理:JIT 编译器会帮助我们将迭代主体编译到IEnumerator.MoveNext()方法中。从上图foreach的执行流程来看,迭代主体是在每次遍历执行到 in 的时候才会调用MoveNext(),所以其迭代器耗时的指令是延迟计算的。

c)LINQ查询的延迟计算原理:通过给LINQ扩展方法传递方法委托,作为yield迭代器的主体,让遍历执行到MoveNext()时才执行耗时的指令。

5.表达式树

表达式树:表达式树允许在运行期间建立对数据源的查询,因为表达式树存储在程序集中。(后续会有详细介绍)

Language Integrated Query(LINQ,语言集成查询)

从这幅图中,我们可以知道LINQ包括五个部分:LINQ to Objects、LINQ to XML、LINQ to SQL、LINQ to DataSet、LINQ to Entities。

目前,还可以下载其他第三方提供程序,例如LINQ to JSON、LINQ to MySQL、LINQ to Amazon、LINQ to Flickr和LINQ to SharePoint。无论使用什么数据源,都可以通过LINQ使用相同的API进行操作。

1.怎样区分LINQ操作时,使用的是哪个LINQ提供程序?

LINQ提供程序的实现方案是:根据命名空间和第一个参数的类型来选择的。实现扩展方法的类的命名空间必须是打开的,否则扩展类就不在作用域内。Eg:在LINQ to Objects中定义的 Where() 方法参数和在 LINQ to Entities中定义的 Where() 方法实现是不同。

  1. // LINQ to Objects:
  2. public static class Enumerable
  3. {
  4. public static IEnumerable<TSource> Where<TSource>(
  5. this IEnumerable<TSource> source, Func<TSource, bool> predicate);
  6. }
  7.  
  8. // LINQ to Entities
  9. public static class Queryable
  10. {
  11. public static IQueryable<TSource> Where<TSource>(
  12. this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
  13.  
  14. }

2.LINQ查询提供几种操作语法?

LINQ查询时有两种语法可供选择:查询表达式(Query Expression)和方法语法(Fluent Syntax)。

.NET公共语言运行库(CLR)并不具有查询表达式的概念。所以,编译器会在程序编译时把查询表达式转换为方法语法,即对扩展方法的调用。所以使用方法语法会让我们更加接近和了解LINQ的实现和本质,并且一些查询只能表示为方法调用。但另一方面,查询表达式通常会比较简单和易读。不管怎样,这两种语法是互相补充和兼容的,我们可以在一个查询中混合使用查询表达式和方法语法。

以下扩展方法存在对应的查询表达式关键字:Where、Select、SelectMany、OrderBy、ThenBy、OrderByDescending、ThenByDescending、GroupBy、Join、GroupJoin。

LINQ查询表达式

书写模版如下:

C#进阶之路(五):Linq初识的更多相关文章

  1. 【SSH进阶之路】Hibernate映射——一对一单向关联映射(五)

    [SSH进阶之路]Hibernate基本原理(一) ,小编介绍了Hibernate的基本原理以及它的核心,採用对象化的思维操作关系型数据库. [SSH进阶之路]Hibernate搭建开发环境+简单实例 ...

  2. C#进阶之路(六):表达式进行类的赋值

    好久没更新这个系列了,最近看.NET CORE源码的时候,发现他的依赖注入模块的很多地方用了表达式拼接实现的.比如如下代码 private Expression<Func<ServiceP ...

  3. python之路:模块初识

    python王者开发之路:模块初识 模块初识我现在讲的确有点早.不过没关系,后面我会详细说模块. 模块,也就是库,是python三剑客之一.这三剑客,函数.库和类,都是由程序编写而成的.之所以我先说模 ...

  4. GO语言的进阶之路-初探GO语言

    GO语言的进阶之路-初探GO语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.为什么我们需要一门新语言 Go语言官方自称,之所以开发Go 语言,是因为“近10年来开发程序之难 ...

  5. Scala进阶之路-Scala中的高级类型

    Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...

  6. GO语言的进阶之路-网络安全之proxy

    GO语言的进阶之路-网络安全之proxy 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在党的带领下,我们大陆的孩子身心健康还是杠杠的,尤其是像我这种农村孩纸,从来不会像<人 ...

  7. GO语言的进阶之路-协程和Channel

    GO语言的进阶之路-协程和Channel 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 看过我之前几篇博客小伙伴可能对Golang语言的语法上了解的差不多了,但是,如果想要你的代码 ...

  8. GO语言的进阶之路-面向对象编程

    GO语言的进阶之路-面向对象编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 当你看完这篇文章之时,我可以说你的Golang算是入门了,何为入门?就是你去看Docker 源码能看 ...

  9. GO语言的进阶之路-面向过程式编程

    GO语言的进阶之路-面向过程式编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们在用Golang写一个小程序的时候,未免会在多个地方调用同一块代码,这个时候如何优化你的代码呢 ...

  10. GO语言的进阶之路-Golang高级数据结构定义

    GO语言的进阶之路-Golang高级数据结构定义 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们之前学习过Golang的基本数据类型,字符串和byte,以及rune也有所了解, ...

随机推荐

  1. Django~1

    一 什么是web框架? 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有 ...

  2. ANSI编码——代码页

    详见wiki: http://zh.wikipedia.org/wiki/%E4%BB%A3%E7%A0%81%E9%A1%B5

  3. Django基础知识MTV

    Django简介 Django是使用Python编写的一个开源Web框架.可以用它来快速搭建一个高性能的网站. Django也是一个MVC框架.但是在Django中,控制器接受用户输入的部分由框架自行 ...

  4. 管道和xargs的区别

    1.概念 管道:将前一个命令的标准输出作为下一个命令的标准输入. xargs:将标准输入传递给下一个命令,作为其参数.(和管道连用)2.区别 2.区别 1:ls|cat是将ls的结果作为一个文件fil ...

  5. Linux 系统密码破解

    (一)CentOS Linux 系统密码破解 1.在grub选项菜单按E进入编辑模式 2.编辑kernel那行 /init 1 (或/single) 3.按B重启 4.进入后执行下列命令 root@# ...

  6. 项目打包部署到tomcat操作步骤

    对于项目部署到tomcat中,需进行一下步骤: 1.对于项目打war包,方式有以下几种:install一下   找到war包的路径即可 另外:在eclipse中,选中项目 1.1 选中Export 1 ...

  7. 多校hdu5726 线段树+预处理

    第一问是没有修改的线段树,第二问暴力预处理,因为gcd的结果不会很多 在预处理阶段需要把每个区间的gcd相等的数量储存起来(用map容器),在一个序列例如:12467,枚举左区间L直到n此处时间为O( ...

  8. 剑指Offer——链表中倒数第k个节点

    Question 输入一个链表,输出该链表中倒数第k个结点. Solution 一种想法就是扫描两边,第一遍求出总的节点个数,第二遍从头开始走n-k个 第二种思想类似于fast-slow指针的方法,f ...

  9. SpringMVC中响应json数据(异步传送)

    1.首先导入3个jar包: jackson-annotations-2.1.5.jar jackson-core-2.1.5.jar jackson-databind-2.1.5.jar JSON所需 ...

  10. hive学习6

    将查询结果集写入另一个表中的时候报了这个错,Dynamic partition strict mode requires at least one static partition column. T ...