LINQ之延迟加载及其原理
这是LINQ(集成化查询)的继续及补充,在前面我已经介绍过,在LINQ中,一个重要的特性就是延迟加载,是指查询操作并不是在查询运算符定义的时候执行,而是在真正使用集合中的数据时才执行(如:在遍历集合时调用MoveNext方法时)。下面是一个简单的实例:
var num = new List<int>();
num.Add();
IEnumerable<int> query = num.Select(n => n * );
num.Add();
foreach (int n in query)
Console.WriteLine(n);
结果输出10 20.在上面的例子中,在创建查询语句后又向集合中加入新元素,这个新元素最终也出现在查询结果中。这就是因为查询语句是在遇到foreach之后才真正执行的,再例如:
Action a = () => Console.WriteLine("Foo");
//没有在控制台输出任何内容
a();
//延迟执行,输出Foo
绝大部分标准的LINQ查询运算符都具有延迟加载这种特性,但也有例外:
- 那些返回单个元素或返回一个数值的运算符,如First或Count。
- 转换运算符:ToArray,ToList,ToDictonnary,ToLookup。
以上这些运算符都会触发LINQ语句立即执行,因为它们的返回值类型不支持延迟加载。
延迟加载的工作原理
LINQ查询运算符之所以有延迟加载功能,是因为每个返回值不是一般的数组或集合,而是一个经过封装的序列,这种序列通常情况下并不直接储存数据元素,它封装并使用运行时传递给它的集合,元素也由其他集合来储存,它实际上只是维护自己与数据集合的一种依赖关系,当有查询请求时,再到它以来的序列中进行真正的查询。查询运算符实际上是封装一系列的转换函数,这种转换函数可以将与之关联的数据转换为各种形式的序列。如果输出集合不需要转换的话,那么就不用执行查询运算符封装的转换操作,这个时候查询运算符实际上就是一个委托,进行数据转发而已。
例如调用Where运算符的时候,在Where内部所做的操作非常简单,根据Lambda表达式中指定的查询条件,对输入集合重新进行了筛选,保留那些符合条件的元素指针引用,当外部遍历Where的返回值时,Where回到它所关联的集合中进行真正的查询,然后返回查询结果。
IEnumerable<int> lessThanTen = new int[] { , , }.Where(n => n < );
当执行lessThanTen操作时,实际上,就是使用where运算符对封装序列进行筛选。
当需要使用一些有特殊功能的运算符时,我们可以自定义实现。例如下面这个实例所示,实现一个自定义的Select运算符:
public static IEnumerable<TResult> Select<TSource,TResult>(
this IEnumerable<TSource> source,Func<TSource,TResult> selector)
{
foreach (TSource element in source)
yield return selector(element);
}
上面这个方法实际上就是在循环中返回yield类型的元素。所以当调用Select和Where查询运算符时,内部操作就是创建一个序列,然后将查询得到的元素存入这个新的序列中。
其实,在LINQ中,延迟加载特性是很重要的,这种设计将查询的转换和查询的执行进行了解耦,这使得我们可以将查询分成多个步骤来创建,有利于查询表达式的书写,而且在执行的时候按照一个完整的结构去查询,减少了对集合的查询次数,这种特性对数据库查询尤其重要。
LINQ之延迟加载及其原理的更多相关文章
- Linq之延迟加载特性
目录 写在前面 系列文章 延迟加载 总结 写在前面 上篇文章介绍了linq中常见的几个关键字,并列举了几个例子,算是对linq如何使用有了初步了解.上篇文章中也提到了,能够使用linq的场合有一个要求 ...
- Linq、延迟加载、直接加载
1.集合常用扩展方法 Where.Max.Min.OrderBy. Select.//投影后的IEnumerable对象可以通过,AsQueryable转换数据类型 First.FirstOrDefa ...
- Linq的延迟加载问题
什么是延迟加载:所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作.可以简单理解为,只有在使用的时候,才会发出sql语句进行查询,数据是分N次读取. 什么是立即加载:所谓立即加载既是所有的 ...
- 转载有个小孩跟我说LINQ(重点讲述Linq中GroupBy的原理及用法)
转载原出处: http://www.cnblogs.com/AaronYang/archive/2013/04/02/2994635.html 小孩LINQ系列导航:(一)(二)(三)(四)(五)(六 ...
- linq之延迟加载和即时加载+标准查询运算符
延迟加载 Linq查询的执行结果是IEnumerable<T>类型,而对IEnumerable<T>,在内部,C#通过yield关键字实现迭代器达到延迟加载的目的.从而使Lin ...
- 图片延时加载原理 和 使用jquery实现的一个图片延迟加载插件(含图片延迟加载原理)
图片加载技术分为:图片预加载和图片延时加载. javascript图片预加载和延时加载的区别主要体现在图片传输到客户端的时机上,都是为了提升用户体验的,延时加载又叫懒加载.两种技术的本质:两者的行为是 ...
- Mybatis 是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询.在 Myba ...
- 使用NHibernate(8)-- 延迟加载
1,延迟加载. 延迟加载,即用到的时候再加载数据.这种机制是非常有情怀的,比如一篇中的用户实体有标签.问题等导航属性,如果只是用到用户名去查询整个实体,则把相关的标签和问题也都加载,性能会比较低.而有 ...
- (第一篇) 一步一步带你了解linq to Object
要想学好linq to object 我们必须要先学习lambda 表达式,学习lambda 表达式呢我们必须了解匿名函数和匿名类及扩展方法,学习匿名函数,我们必须学会委托,这是本文的宗旨.下面开始第 ...
随机推荐
- VS轻松开发Node.js应用
PTVS开发团队又开发出一款可以在VS里编写Node.js应用程序的插件--NTVS(Node.js Tools for Visual Studio),开发者可以在VS里轻松开发Node.js应用. ...
- dagger2 备注
dagger 2是android下的IOC框架,类似java服务端的spring,但功能上远没有其强大.个人理解不管是APP还是服务端依赖注入的本质都是一样的,用于解耦某个服务的定义和实现.我自己给出 ...
- Mycat 全局系列号
标签:utf8 概述 本篇文章介绍mycat怎样在分库分表的情况下保证主键的全局唯一方法,接下来就来分析三种方法各自的优缺点. 配置 文件方式获取 1.修改server配置文件 vim server. ...
- Linux 配置YUM
标签:MYSQL/linux 概述 文章主要介绍配置163,mysql,epel这三个yum源. 目录 概述 步骤 下载安装包 卸载自带的yum 安装yum包 添加yum 总结 步骤 安装163源 注 ...
- 说说设计模式~大话目录(Design Pattern)
回到占占推荐博客索引 设计模式(Design pattern)与其它知识不同,它没有华丽的外表,没有吸引人的工具去实现,它是一种心法,一种内功,如果你希望在软件开发领域有一种新的突破,一个质的飞越,那 ...
- iOS-Objective-C基础
一.Foundation框架 概述 我们前面的章节中就一直新建Cocoa Class,那么Cocoa到底是什么,它和我们前面以及后面要讲的内容到底有什么关系呢?Objective-C开发中经常用到NS ...
- Python学习路径及练手项目合集
Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159
- SQL注入
@org.junit.Test public void testLogin() { CardDAO cd=new CardDAO(); if(cd.dengru("' or 1 = 1--& ...
- SSRS 报表点击 Preview 显示失败
今天使用Remote Desktop 链接到Remote Server,在SSDT中创建一个RDL文件,点击PreView预览时,出现以下错误信息 查看details information ==== ...
- Windows无法安装到这个磁盘。请确保在计算机的BIOS菜单中启用了磁盘控制器
今天一朋友问我这个问题,呃,以前我也遇到过,但忘记记录了,这次就记录一下吧,就懒得打字了,图片里面很清楚了 不说点什么的话是不是太水了O(∩_∩)O~,好吧扩充一下: Windows无法安装到这个磁盘 ...