C#进阶之路(五):Linq初识
关于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委托,是微软为我们预定义的常用委托,封装一个具有:零个或多个指定类型的输入参数并返回一个指定类型的结果值的方法。
示例:
static void Main(string[] args)
{
// 委托函数
Func<string, string, string> func1 = Hello;
// 匿名方法
Func<string, string, string> func2 =
delegate(string a, string b)
{
return "欢迎光临我的博客" + Environment.NewLine + a + " " + b;
};
// Lambda表达式
Func<string, string, string> func3 =
(a, b) => { return "欢迎光临我的博客" + Environment.NewLine + a + " " + b; };
// 调用Func委托
string helloStr = func2("滴答的雨", @"http://www.cnblogs.com/heyuquan/");
Console.WriteLine(helloStr);
} static string Hello(string a, string b)
{
return "欢迎光临我的博客" + Environment.NewLine + a + " " + b;
}
3.扩展方法
1)扩展方法声明在静态类中,定义为一个静态方法,其第一个参数需要使用this关键字标识,指示它所扩展的类型。
2)扩展方法可以将方法写入最初没有提供该方法的类中。还可以把方法添加到实现某个接口的任何类中,这样多个类就可以使用相同的实现代码。(LINQ中,System.Linq.Queryable.cs和System.Linq.Enumerable.cs 正是对接口添加扩展方法)
3)扩展方法虽定义为一个静态方法,但其调用时不必提供定义静态方法的类名,只需引入对应的命名空间,访问方式同实例方法。
4)扩展方法不能访问它所扩展的类型的私有成员。
示例:
public static IEnumerable<TSource> MyWhere<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource item in source)
{
if (predicate(item))
yield return item;
}
}
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() 方法实现是不同。
// LINQ to Objects:
public static class Enumerable
{
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate);
} // LINQ to Entities
public static class Queryable
{
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate); }
2.LINQ查询提供几种操作语法?
LINQ查询时有两种语法可供选择:查询表达式(Query Expression)和方法语法(Fluent Syntax)。
.NET公共语言运行库(CLR)并不具有查询表达式的概念。所以,编译器会在程序编译时把查询表达式转换为方法语法,即对扩展方法的调用。所以使用方法语法会让我们更加接近和了解LINQ的实现和本质,并且一些查询只能表示为方法调用。但另一方面,查询表达式通常会比较简单和易读。不管怎样,这两种语法是互相补充和兼容的,我们可以在一个查询中混合使用查询表达式和方法语法。
以下扩展方法存在对应的查询表达式关键字:Where、Select、SelectMany、OrderBy、ThenBy、OrderByDescending、ThenByDescending、GroupBy、Join、GroupJoin。
LINQ查询表达式
书写模版如下:
C#进阶之路(五):Linq初识的更多相关文章
- 【SSH进阶之路】Hibernate映射——一对一单向关联映射(五)
[SSH进阶之路]Hibernate基本原理(一) ,小编介绍了Hibernate的基本原理以及它的核心,採用对象化的思维操作关系型数据库. [SSH进阶之路]Hibernate搭建开发环境+简单实例 ...
- C#进阶之路(六):表达式进行类的赋值
好久没更新这个系列了,最近看.NET CORE源码的时候,发现他的依赖注入模块的很多地方用了表达式拼接实现的.比如如下代码 private Expression<Func<ServiceP ...
- python之路:模块初识
python王者开发之路:模块初识 模块初识我现在讲的确有点早.不过没关系,后面我会详细说模块. 模块,也就是库,是python三剑客之一.这三剑客,函数.库和类,都是由程序编写而成的.之所以我先说模 ...
- GO语言的进阶之路-初探GO语言
GO语言的进阶之路-初探GO语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.为什么我们需要一门新语言 Go语言官方自称,之所以开发Go 语言,是因为“近10年来开发程序之难 ...
- Scala进阶之路-Scala中的高级类型
Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...
- GO语言的进阶之路-网络安全之proxy
GO语言的进阶之路-网络安全之proxy 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在党的带领下,我们大陆的孩子身心健康还是杠杠的,尤其是像我这种农村孩纸,从来不会像<人 ...
- GO语言的进阶之路-协程和Channel
GO语言的进阶之路-协程和Channel 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 看过我之前几篇博客小伙伴可能对Golang语言的语法上了解的差不多了,但是,如果想要你的代码 ...
- GO语言的进阶之路-面向对象编程
GO语言的进阶之路-面向对象编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 当你看完这篇文章之时,我可以说你的Golang算是入门了,何为入门?就是你去看Docker 源码能看 ...
- GO语言的进阶之路-面向过程式编程
GO语言的进阶之路-面向过程式编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们在用Golang写一个小程序的时候,未免会在多个地方调用同一块代码,这个时候如何优化你的代码呢 ...
- GO语言的进阶之路-Golang高级数据结构定义
GO语言的进阶之路-Golang高级数据结构定义 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们之前学习过Golang的基本数据类型,字符串和byte,以及rune也有所了解, ...
随机推荐
- asp.net IRequiresSessionState
在一般处理程序中,使用context.Session对象,必须先继承IRequiresSessionState接口. System.Web.SessionState.IRequiresSessionS ...
- webpack基础配置
webpack运行规则: Webpack 会给每个模块分配一个唯一的id并通过这个id索引和访问模块.在页面启动时,会先执行入口文件中的代码,其它模块会在运行 require 的时候再执行. 运行时主 ...
- grads 读取shp
自从GrADS2.0.a8版本开始,GrADS引入了对shp图形的支持,关于此格式在这里不多说, 于是今晚就简单测试了一下最简单画图和查询命令(后续还将测试输出shp图形的命令) 测试数据采用的 ...
- sql两张表关联更新字段
记录,推荐使用第三种,个人觉得比较好 --第一种写法,之前一直用,没有在意 UPDATE sr_t_TCodeUserReciveCfg SET fUserID=a.fUserID,fImportFl ...
- maven使用(一)
在官网上下载maven的包http://maven.apache.org/download.cgi 下载压缩包apache-maven-3.3.9-bin.zip 在环境变量中新建变量: M2-HOM ...
- CSS实现三角形图标的原理!!!!今天总算弄懂了。
网页中经常有一种三角形的图标,鼠标点一下会弹出一个下拉菜单之类的(之前淘宝也有,不过现在改版好像没有了) 之前以为是个png图标背景,后来在bootstrap中看到有一个图标样式叫做caret的用来实 ...
- OS路径模块命令
os.remove():删除指定文件os.rmdir():删除指定目录os.mkdir():创建单级目录os.makedirs():创建多级目录os.listdir(dirname):列出dirnam ...
- Java中Arrays.sort()和Collections.sort()
1.简单示例 sort方法的使用非常的简单明了,下面的例子中,先定义一个比较Dog大小的Comparator,然后将其实例对象作为参数传给sort方法,通过此示例,你应该能够快速掌握Arrays.so ...
- Go struct tag
struct成员变量标签(Tag)说明 要比较详细的了解这个,要先了解一下golang的基础,在golang中,命名都是推荐都是用驼峰方式,并且在首字母大小写有特殊的语法含义:包外无法引用.但是由经常 ...
- 8.14比赛j题 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87813#overview
就我个人来说我觉得这道题其实不用写题解,只是因为做的时候错了一次,如果不是队友细心,我根本会错下去,所以我感觉自己必须强大#include<stdio.h> #include<str ...