Linq中的绝大多数查询运算符都有延迟执行的特性,查询并不是在查询创建的时候执行,而是在遍历的时候执行,也就是在enumerator的MoveNext()方法被调用的时候执行,大说数Linq查询操作实例方法返回的都是IEnumerable<T>,所以只有在使用foreach遍历的时候,查询方法才能被真正的执行.请参考C# 通过IEnumberable接口和IEnumerator接口实现自定义集合类型foreach功能

示例代码如下:

List<int> list=new List<int>();
list.AddRange(new int[]{ , , , , });
IEnumerable<int> result = list.Where(n => n >= );
list.Add();
foreach (var n in result)
{
Console.WriteLine(n);
}

输出结果一目了然,当创建完查询之后添加的元素也包含到了结果集中,说明查询并没有立即执行,而是在使用foreach遍历之后才执行,这种特性就是Linq的延迟执行.

不止Where查询操作符是这样的,其他的只要返回的是IEnumerable<T>对象的都有延迟执行特性.

注:其他的一些像First、Count、ToArray、ToList、ToDictionary、ToLookup这些都是立即执行的.

当然,对于Linq来说,延迟执行是非常重要的,因为它把查询的创建和查询的执行解耦了,这让我们可以像创建SQL查询那样,分成多个步骤来创建我们的LINQ查询。

重复执行

使用导致延迟执行的查询操作符进行查询操作,并且两次或者两次以上的使用foreach,会导致查询重复执行,重复执行在以下两种情况下,绝对是不好的:

1、当需要在一个确定点保存查询的结果时,因为延迟执行并不会在创建查询之后马上得到查询结果集,所以必须使用上面提到的ToArray、ToList等方法使查询立即执行得到结果集并进行存储,代码如下:

List<int> list=new List<int>();
list.AddRange(new int[]{ , , , , });
IEnumerable<int> result = list.Where(n => n >= ).ToList();
list.Add();
foreach (var n in result)
{
Console.WriteLine(n);
}

例子不是贴切,但是意思到了,此时的查询是立即执行.

2、有些查询比较耗时,比如对一个非常大的数据集进行操作或者通过Linq远程操作数据库操作数据时,这个时候的重复执行会严重影响性能.

延迟执行的实现原理

查询运算符通过返回装饰者sequence(decorator sequence)来支持延迟执行。

和传统的集合类型如array,linked list不同,一个装饰者sequence并没有自己用来存放元素的底层结构,而是包装了我们在运行时提供的另外一个sequence。此后当我们从装饰者sequence中请求数据时,它就会转而从包装的sequence中请求数据。

比如调用Where会创建一个装饰者sequence,其中保存了输入sequence的引用、lambda表达式还有其他提供的参数。下面的查询对应的装饰者sequence如图所示:

        IEnumerable<int> lessThanTen = new int[] { 5, 12, 3 }.Where(n => n < 10);

当我们遍历lessThanTen时,实际上我们是在通过Where装饰者从Array中查找数据。

而查询运算符链接创建了一个多层的装饰者,每个查询运算符都会实例化一个装饰者来包装前一个sequence,比如下面的query和对应的多层装饰者sequence:

            IEnumerable<int> query = new int[] { 5, 12, 3 }
.Where(n => n < 10)
.OrderBy(n => n)
.Select(n => n * 10);

在我们遍历query时,我们其实是在通过一个装饰者链来查询最初的array。

需要注意的是,如果在上面的查询后面加上一个转换运算符如ToList,那么query会被立即执行,这样,单个list就会取代上面的整个对象模型。

Linq基础知识之延迟执行的更多相关文章

  1. Linq基础知识小记四之操作EF

    1.EF简介 EF之于Linq,EF是一种包含Linq功能对象关系映射技术.EF对数据库架构和我们查询的类型进行更好的解耦,使用EF,我们查询的对象不再是C#类,而是更高层的抽象:Entity Dat ...

  2. Linq基础知识小记三

    1.子查询 Linq中的子查询思想和Sql中的子查询其实差不多, 对于方法语法,一个子查询包含在另一个子查询的Lambda表达式中,代码如下: string[] names = { "Jam ...

  3. Linq基础知识小记二

    书写Linq查询有两种方法,第一种是通过方法语法(也就是扩展方法),第二种是查询表达式语法. 1.方法语法 方法语法就是通过扩展方法和Lambda表达式来创建查询 (1).链式查询 这种查询方式很多语 ...

  4. Linq基础知识小记一

    1.LINQ(语言级集成查询)的作用就是提供一种统一且对称的方式,让程序员在广义的数据上获取和操作数据.广义的数据包括XML文档数据.元数据.System.Data.dll和System.Data.S ...

  5. Linq基础知识

    开发人员不需要关心将要访问的是关系数据库还是XML数据,或是远程对象,它都采用同样的访问方式. Linq包含一系列的查询技术,其中Linq到对象是对内存进行操作,LINQ到SQL是对数据库的操作,LI ...

  6. LINQ之路 6:延迟执行(Deferred Execution)

    LINQ中大部分查询运算符都有一个非常重要的特性:延迟执行.这意味着,他们不是在查询创建的时候执行,而是在遍历的时候执行(换句话说,当enumerator的MoveNext方法被调用时).让我们考虑下 ...

  7. linq 延迟执行带来的困扰

    有这样一个案例: var filteredResult = from f in orgFileList select f; ; i < WorkStatusFilters.ListWorkSta ...

  8. Linq延迟执行

    LINQ中大部分查询运算符都有一个非常重要的特性:延迟执行.这意味着,他们不是在查询创建的时候执行,而是在遍历的时候执行(换句话说,当enumerator的MoveNext方法被调用时).让我们考虑下 ...

  9. C#中Linq延迟执行问题

    本文来自:http://msdn.microsoft.com/zh-cn/library/bb399393(v=vs.110).aspx http://www.cnblogs.com/zhanglin ...

随机推荐

  1. BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 8112  Solved: 2569[Submit] ...

  2. # 20155204 2016-2017-2 《Java程序设计》第五周学习总结

    20155204 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 Java中所有错误都会被打包为对象,运用try.catch,可以在错误发生时显示友好的错误信 ...

  3. CDialog

    对话框和对话框类CDialog 对话框经常被使用,因为对话框可以从模板创建,而对话框模板是可以使用资源编辑器方便地进行编辑的. 模式和无模式对话框 对话框分两种类型,模式对话框和无模式对话框. 模式对 ...

  4. android注解处理技术APT

    APT(Annotation Processing Tool)是java的注解处理技术,它对源代码文件进行检测找出其中的Annotation,根据注解和注解处理器和相应的apt自动生成代码. Anno ...

  5. Gridview的RowDataBound事件可以做很多事情

    protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)        {            //如果是绑 ...

  6. calltree+graphviz 绘出项目函数调用图

    install calltree: download from http://linux.softpedia.com/progDownload/calltree-Download-971.html f ...

  7. GoF设计模式学习-单例模式

    1.目的 控制实例的个数,类设计者应该保证只有一个实例,不能将此责任[只有一个实例]强制交给类使用者. 2.整体实现 1.单线程单例模式的实现. using System; using System. ...

  8. Latex中Matlab代码的环境

    需要用到listings宏包 使用方法: 导言区\usepackage{listings}\lstset{language=Matlab}      %代码语言使用的是matlab\lstset{br ...

  9. Python学习-22.Python中的函数——type

    type函数可以检测任何值或变量的类型. 例子: def printType(var): print(type(var)) class TestClass: pass printType(1) pri ...

  10. MYSQL的数据连接超时时间设置

    大规模多线程操作事务的时候,有时候打开一个链接,会进行等待,这时候如果数据库的超时时间设置的过短,就可能会出现,数据链接自动被释放,当然设置过大也不好,慢SQL或其他因素引起的链接过长,导致整个系统被 ...