C#表达式树的初步了解
在很早以前就听说过表达式树了,但并没有去了解它。虽然自己用过linq to sql和linq to entity,但也就用着就用着,并没有去深究c#代码怎么会生成sql代码而不是IL。废话不多说了,开写吧!
.net里表达式树核心概念就是:将代码作为数据。它将一些代码表示为一个对象树,树中的每个节点本身都是一个表达式,不同的表达式类型代表能在代码中执行不同操作:二元操作,一元操作,方法调用等等。
System.Linq.Expressions命名空间包含了代表表达式的各个类。所有的表达式类都从Expression类派生,Expression是个抽象类,主要包含的是一些静态的方法,这些方法用于生成其他表达式类的实例。Expression类还包含了两个重要属性:
1.Type属性:代表了表达式求值结果的类型。比如,一个表达式是要获取一个字符串的Length属性,那么该表达式的Type属性应为int类型
2.NodeType属性:代表了表达式的种类。这个种类表示成ExpressionType枚举的一个成员:LessThan,Invoke,Multiply,MemberAccess等等(有80几种,汗!)。
一个表达式树的简单例子
static void Main(string[] args)
{
Expression firstArg = Expression.Constant();
Expression secondArg = Expression.Constant();
Expression add = Expression.Add(firstArg, secondArg); Console.WriteLine(add);
}
输出结果:
上面的代码将会生成如下图的表达式树:

值得注意的是,表达式中“叶”表达式在代码中是最先创建的:表达式是自下而上构建的。这是由“表达式不易变”这一事实实现的。
将表达式树编译成委托
LambdaExpression是从Expression派生的类型。泛型类Expression<TDelegate>是从LambdaExpression派生的,其中泛型参数TDelegate必须是委托类型。
LambdaExpression有个Compile方法能创建恰当类型的一个委托。而Expression<TDelegate>的Compile方法返回TDelegate类型的委托。来看看下面的例子:
static void Main(string[] args)
{
Expression firstArg = Expression.Constant();
Expression secondArg = Expression.Constant();
Expression add = Expression.Add(firstArg, secondArg); Expression<Func<int>> func = Expression.Lambda<Func<int>>(add);
Func<int> compiled = func.Compile();
Console.WriteLine(compiled());
}
我们通过Expression.Lambda<TDelegate>(Expression expression)方法来创建Expression<TDelegate>类型对象,再调用其Compile方法获取表达式树编译出的委托实例。
将C# Lambda表达式转换成表达式树
我们知道Lambda表达式能显示或隐式地转换成恰当的委托实例。但是,编译器也能很轻松的将Lambda表达式构建为一个表达式树:
//将Lambda表达式转换成表达式树
Expression<Func<int>> return5 = () => ;
但是,并不是所有的Lambda表达式都能转换成表达式树,有一些限制:不能将带有一个语句块的Lambda转换成一个表达式树-----只有对单个表达式进行求值得Lambda才可以。表达式中不能包含赋值操作,因为表达式树中表示不了这种操作。还有其他一些较少见的限制,总而言之,如果存在转换问题,你会在编译时发现。
位于Linq核心的表达式树
表达式树可以说是Linq的核心之一,为什么是Linq的核心之一呢?因为表达式树使得c#不再是仅仅能编译成IL,我们可以通过c#生成一个表达式树,将结果作为一个中间格式,在将其转换成目标平台上的本机语言。比如SQL。我们常用的Linq to sql就是这样生成SQL的。
下图展示了Linq to Objects和Linq to SQL的不同路径:

资料参考于《深入理解c#》第二版
C#表达式树的初步了解的更多相关文章
- C# 高性能对象映射(表达式树实现)
前言 上篇简单实现了对象映射,针对数组,集合,嵌套类并没有给出实现,这一篇继续完善细节. 开源对象映射类库映射分析 1.AutoMapper 实现原理:主要通过表达式树Api 实现对象映射 优点: . ...
- C# 表达式树讲解(一)
一.前言 一直想写一篇Dpper的定制化扩展的文章,但是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必须要知道表达式树的相关知识点.我希望能通过对各个模块的知识点或者运用能够多 ...
- C# 表达式树遍历(二)
一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...
- 再讲IQueryable<T>,揭开表达式树的神秘面纱
接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- 轻量级表达式树解析框架Faller
有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...
- 用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树
这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五 ...
- LinqToDB 源码分析——处理表达式树
处理表达式树可以说是所有要实现Linq To SQL的重点,同时他也是难点.笔者看完作者在LinqToDB框架里面对于这一部分的设计之后,心里有一点不知所然.由于很多代码没有文字注解.所以笔者只能接合 ...
- LinqToDB 源码分析——生成表达式树
当我们知道了Linq查询要用到的数据库信息之后.接下就是生成对应的表达式树.在前面的章节里面笔者就已经介绍过.生成表达式树是事实离不开IQueryable<T>接口.而处理表达式树离不开I ...
随机推荐
- linux内核分析 课程总结
Linux内核分析 链接汇总 Linux内核分析第一周学习总结--计算机是如何工作的 Linux内核分析第二周学习总结--操作系统是如何工作的 Linux内核分析第三周学习总结--构造一个简单的Lin ...
- PowerCMD——cmd的命令行工具
之前就想整理一下程序员经常使用的一些工具,最近有时间正好整理一下. 有句话叫做:“工欲善其事必先利其器”,而我就算是搜集工具组装成一个系列——善事利器,来记录一下工作学习中常用的一些工具. 总结起来, ...
- Jenkins进阶系列之——15Maven获取Jenkins的Subversion的版本号
各位小伙伴们在工作中总是会碰到各种各样的奇葩需求,今天给大家说说Maven怎么在Jenkins中获取Subversion的版本号. Jenkins自己的环境变量中包含了很多有用的的参数,详情查看:ht ...
- C#基础之枚举
1.认识Enum 以前一直以为Enum是值类型,在VS中查看Enum的定义时才发现它是一个抽象的类.但是这个类很奇怪,Enum继承了ValueType这个很熟悉的值类型基类,它是唯一一个继承自Valu ...
- 使用Let’s Encrypt轻松配置https站点
使用Let's Encrypt轻松配置https站点 https不仅能提高网站安全,更是被搜索引擎纳入排名的因素之一. 2015年10月份,微博上偶然看到Let's Encrypt 推出了beta版, ...
- display:inline-block的坑
一直用display:inline-block做某种导航栏还很爽,突然有一个柱状图的需求便也这么做了,于是成功被坑. 简简单单个需求,大致这样 只用几个li加上display:inline-block ...
- css平时写的时候注意的
1.如果用absolute的时候一定要注意,bottom如果为)的话,一定要注意上一级的relative是否有height. 2.chrome浏览器,我们需要注意的是width包含了padding,但 ...
- PHP使用DateTime类做时间日期到字符串转换
PHP关于时间日期的处理不是很规范,简单就简单了,就是不知道输入的字符串是否能够正确转化为需要的DateTime类型. 面向对象的PHP应该使用DateTime类来做string和dateTime的转 ...
- Go语言开发环境搭建
1.Go的安装 (1)下载go安装程序 下载地址:https://golang.org/dl/ (墙内下载地址http://www.golangtc.com/download),如果是您的系统是win ...
- Java-Vector
package 集合类.list类; import java.util.Vector; public class Vector类 { public static void main(String[] ...