在很早以前就听说过表达式树了,但并没有去了解它。虽然自己用过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#表达式树的初步了解的更多相关文章

  1. C# 高性能对象映射(表达式树实现)

    前言 上篇简单实现了对象映射,针对数组,集合,嵌套类并没有给出实现,这一篇继续完善细节. 开源对象映射类库映射分析 1.AutoMapper 实现原理:主要通过表达式树Api 实现对象映射 优点: . ...

  2. C# 表达式树讲解(一)

    一.前言 一直想写一篇Dpper的定制化扩展的文章,但是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必须要知道表达式树的相关知识点.我希望能通过对各个模块的知识点或者运用能够多 ...

  3. C# 表达式树遍历(二)

    一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...

  4. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  5. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  6. 轻量级表达式树解析框架Faller

    有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...

  7. 用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树

    这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五 ...

  8. LinqToDB 源码分析——处理表达式树

    处理表达式树可以说是所有要实现Linq To SQL的重点,同时他也是难点.笔者看完作者在LinqToDB框架里面对于这一部分的设计之后,心里有一点不知所然.由于很多代码没有文字注解.所以笔者只能接合 ...

  9. LinqToDB 源码分析——生成表达式树

    当我们知道了Linq查询要用到的数据库信息之后.接下就是生成对应的表达式树.在前面的章节里面笔者就已经介绍过.生成表达式树是事实离不开IQueryable<T>接口.而处理表达式树离不开I ...

随机推荐

  1. [CareerCup] 7.1 Basketball Shooting Game 投篮游戏

    7.1 You have a basketball hoop and someone says that you can play one of two games. Game 1: You get ...

  2. LeetCode 笔记22 Distinct Subsequences 动态规划需要冷静

    Distinct Subsequences Given a string S and a string T, count the number of distinct subsequences of  ...

  3. json跨域原理及解决方法

    这一篇文章呢,主要是之前一直听别人讲json跨域跨域,但是还是一头雾水,只知其一,于是一怒之下,翻阅各种资料,如果有不正确的地方,劳烦指正一下^_^ 首先,先了解浏览器有一个很重要安全性限制,即为同源 ...

  4. WP8.1&Win10幸运大转盘源码分享

    先AD一下我的群:Win10开发者群:53078485 最近在写一个APP,其中需要一个转盘动画的源码,找了很多但是都没有找到,无奈只好自己来写,写完效果自己还是比较满意的,分享出来,有需要的童鞋可以 ...

  5. 怎样写 OpenStack Neutron 的 Extension (二)

    接着之前一篇文章,再来谈谈 Extension 的具体实现问题.我使用的是本地数据库加远程API调用的方法,所以先要定义一下数据库中 myextension 如何存储.首先,我们可以在自己的 plug ...

  6. Javascript 里的 in

    写js的时候需要遍历一个对象的属性,把属性名和属性值都提出来,之前没遇到这种需求,查了一下可以用for in的方式. var obj = { "key1":"value1 ...

  7. css为什么要用悬浮

    如果这个100px的宽度是一个Img,横内元素.右边也是横内元素的话和块级元素是不同的. 2.文字环绕图片. div下有个img然后有个span标签 img最好悬浮,悬浮虽然说脱离文档,但是还是占空间 ...

  8. jQuery应用之(三)jQuery链

    从前文的实例中,我们按到jQuery语句可以链接在一起,这不仅可以缩短代码长度,而且很多时候可以实现特殊的效果. <script type="text/javascript" ...

  9. javascript去掉字符串前后空格

    使用场景 当我们进行一些页面编辑时,字符串前后的空格,通常是无效的.因此需要在获取信息时,进行过滤. 比如: 输入:[空格][空格]a[空格]b[空格][空格][空格] 得到:a[空格]b 代码如下: ...

  10. 每天一个linux命令(8):cat 命令

    cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 1.命令格式: cat [选项] [文件] ...