IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树
关于IEnumerable和IQueryable的区别,这事还要从泛型委托Func<T>说起。来看一个简单的泛型委托例子:
class Program{static void Main(string[] args){Func<int, bool> f = i => i > 5;Console.WriteLine(f(3));Console.WriteLine(f(10));Console.ReadKey();}}
Func<T>是"语法糖",实际上,编译器在内部会生成一个临时方法,再执行该方法。等同于如下:
class Program{static void Main(string[] args){Func<int, bool> f = DoSth;Console.WriteLine(f(3));Console.ReadKey();}static bool DoSth(int i){return i > 5;}}
以上,.NET内部运作的路径是:编写C#代码→编译器编译成中间语言IL→运行时JIT编译成本地语言执行
■ 使用表达式树 Expression Tree
可是,有时候我们希望在运行时执行代码,该怎么办呢?
.NET为我们提供了Expression Tree,允许我们在运行时执行代码。
比如以上Func<int, bool> f = i => i > 5;这个表达式,Expression Tree这样理解这个表达式:
○ f是Expression<Func<int, bool>>类型,级Expression<TDelegate>类型
○ =>被理解成BinaryExpression类型
○ =>左右两边的i被理解成ParameterExpression
○ =>右边的5被理解成ConstantExpression
于是,如果我们用Expression Tree,在运行时执行代码,可以按如下写:
class Program{static void Main(string[] args){//Func<int, bool> f = i => i > 5;ParameterExpression iParam = Expression.Parameter(typeof (int), "i");ConstantExpression constExp = Expression.Constant(5, typeof (int));BinaryExpression greaterThan = Expression.GreaterThan(iParam, constExp);Expression<Func<int, bool>> f = Expression.Lambda<Func<int, bool>>(greaterThan, iParam);Func<int, bool> myDele = f.Compile();Console.WriteLine(myDele(3));Console.WriteLine(myDele(10));Console.ReadKey();}}
■ IQueryable和IEnumerable的区别
现在,可以看一个IEnumerable的例子了:
class Program{static void Main(string[] args){int[] intArr = new[] {1, 2, 3, 6, 8};IEnumerable<int> result = Enumerable.Where(intArr, i => i > 5);foreach (var item in result){Console.WriteLine(item);}Console.ReadKey();}}
来看一下Enumerable,实现了IEnumerable接口,它的定义:
再来看Queryable,实现了IQueryable接口,它的定义:
发现,Enumerable和Queryable很多方法同名,但参数接收的参数类型是不一样的,Enumerable接收的参数类型是委托Func<TDelegate>,Querable接收的参数类型是Expression<Func<TDelegate>>,其类型是Expression Tree,是表达式树。
所以,有关IEnumerable<T>的表达式是在编译期确定的,有关IQueryable<T>的表达式是在运行时确定的。
■ 在Entity Framework应用实例中体会IQueryable<T>
首先在控制台应用程序中应用Entity Framework组件。
创建有关Entity Framework的上下文类,类,初始数据:
public class Person{[Key]public int ID { get; set; }public string Name { get; set; }public int Age { get; set; }}public class MyContext : DbContext{public MyContext() : base("myConn"){Database.SetInitializer(new DbInirializer());}public DbSet<Person> People { get; set; }}public class DbInirializer : CreateDatabaseIfNotExists<MyContext>{protected override void Seed(MyContext context){IList<Person> people = new List<Person>();people.Add(new Person(){Name = "张三",Age = 21});people.Add(new Person() { Name = "李四", Age = 22 });people.Add(new Person() { Name = "赵五", Age = 23 });foreach (var item in people){context.People.Add(item);}base.Seed(context);}}
以上,如果转到DbSet的定义,我们可以看到DbSet实现了IQueryable接口。
配置连接字符串。
<configuration><configSections><!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --><section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /></configSections><connectionStrings><add name="myConn"connectionString="Data Source=.;User=yourusename;Password=yourpassword;Initial Catalog=MyTest;Integrated Security=True"providerName="System.Data.SqlClient"/></connectionStrings><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /></startup><entityFramework><defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" /><providers><provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /></providers></entityFramework></configuration>
在主程序中:
class Program{static void Main(string[] args){using (var context = new MyContext()){foreach (var item in context.People){Console.WriteLine(item.Name);}}Console.ReadKey();}}
现在来体会IQueryable<T>的一些特性。
我们知道,DbSet实现了IQuerayble接口,于是上下文的的People属性类型是IQueryable<Person>。
通过,
IQueryable<Person> people = context.People;
得到的people是表达式,是sql语句,现在尝试打印不同情况下的people表达式。
class Program{static void Main(string[] args){using (var context = new MyContext()){IQueryable<Person> people = context.People;var r = new Random();Func<bool> rBool = () => r.Next()%2 == 0;Console.WriteLine(people);if (rBool()){people = people.Where(p => p.Age > 21);Console.WriteLine(people);}else{people = people.OrderBy(p => p.Age);Console.WriteLine(people);}}Console.ReadKey();}}
由此可以看出:IQueryable呈现给我们的是表达式而不是集合,通过这个表达式可以按需加载满足条件的数据。
IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树的更多相关文章
- IEnumerable 与 Iqueryable 的区别
IEnumerable 和 IQueryable 共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable<T> 的对象上运行,另一组在类型为 IQueryable&l ...
- IEnumerable和IQueryable的区别
转自:http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...
- IEnumerable和IQueryable在使用时的区别
最近在调研数据库查询时因使用IEnumerable进行Linq to entity的操作,造成数据库访问缓慢.此文讲述的便是IEnumerable和IQueryable的区别. 微软对IEnumera ...
- Entity Framework返回IEnumerable还是IQueryable?
在使用EF的过程中,我们常常使用repository模式,本文就在repository层的返回值是IEnumerable类型还是IQueryable进行探讨. 阅读目录: 一.什么是Repositor ...
- 再讲IQueryable<T>,揭开表达式树的神秘面纱
接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...
- 【转】再讲IQueryable<T>,揭开表达式树的神秘面纱
[转]再讲IQueryable<T>,揭开表达式树的神秘面纱 接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个 ...
- IEnumerable 和 IQueryable 区别
IQueryable继承自IEnumerable,所以对于数据遍历来说,它们没有区别. 但是IQueryable的优势是它有表达式树,所有对于IQueryable的过滤,排序等操作,都会先缓存到表达式 ...
- IEnumerable,IQueryable的区别
IEnumerable,IQueryable之前世今生 IEnumerable<T>在.Net2.0中我们已经很熟悉了.你想要利用Foreach迭代吗?实现IEnumerable<T ...
- IEnumerable<T>和IQueryable<T>区别
LINQ查询方法一共提供了两种扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合进行扩展:Queryab ...
随机推荐
- ida自动编译配置
这个勾选上,就会出现
- Smooth Face Tracking with OpenCV
先马克下,回头跑试试:http://synaptitude.me/blog/smooth-face-tracking-using-opencv/ GitHub:https://github.com/S ...
- v-if案例解析(element-ui form-item 结合 v-if 动态生成rule规则\表单元素,表单无法验证问题剖析 )
fire 读在最前面: 1.此文章衔接Vue 虚拟Dom 及 部分生命周期初探,相关整体知识点请先阅读后再继续本文阅读 问:当v-if为true时,会重新渲染相关dom节点吗? <child v ...
- Java编程的逻辑 (55) - 容器类总结
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- .NetCore 中使用AppMetrics向InfluxDB中添加监控数据并通过Grafana图像分析
考虑到分布式部署监控环境是所有的请求情况,所以这一块一般在网关GateWay里面加比较省事,聚合在一起的,如果放在api服务中,如果只有1个还好,一旦部署Node多是很痛苦的事情 这天需要添加的Nug ...
- yum源安装php报错缺少libmcrypt.so.4()(64bit)库
https://blog.csdn.net/programercch/article/details/56282184
- LOOPS 概率dp
题意:迷宫是一个R*C的布局,每个格子中给出停留在原地,往右走一个,往下走一格的概率,起点在(1,1),终点在(R,C),每走一格消耗两点能量,求出最后所需要的能量期望 简单概率dp 注意 原地不 ...
- 004.LVM缩减
一 缩减步骤 卸载挂载点 检查文件系统 调整分区大小 缩减LV大小 重新挂载并检查 注意: 1 减少文件的大小一定需要按照上面提高的4个规定动作顺序来做,在缩减LV大小前,首先要缩减filesyste ...
- 001.NFS简介
一 简介 NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向外公布.功能是通过网络让不同的机器.不同的操作系统能够 ...
- MVC+easyui,写个树
前言:网上关于编写组织机构树的教程并不少,我第一次写树的时候也是在网上借鉴别人的技术,走了一些弯路写下了树.是因为这些教程都不是很全面,对于编程新手来说跳跃性太强.所以趁着闲暇时期,我用心的写个树,供 ...