一、表达式树入门

Lambda表达式树很复杂,从概念上很难理解清楚,一句话,表达式树是一种数据结构!这里我们通过下面的这个例子来理解一下表达式树,你就能看个大概:

lambda表达式树动态创建方法

static void Main(string[] args)
{
//i*j+w*x
ParameterExpression a = Expression.Parameter(typeof(int),"i"); //创建一个表达式树中的参数,作为一个节点,这里是最下层的节点
ParameterExpression b = Expression.Parameter(typeof(int),"j");
BinaryExpression r1 = Expression.Multiply(a,b); //这里i*j,生成表达式树中的一个节点,比上面节点高一级 ParameterExpression c = Expression.Parameter(typeof(int), "w");
ParameterExpression d = Expression.Parameter(typeof(int), "x");
BinaryExpression r2 = Expression.Multiply(c, d); BinaryExpression result = Expression.Add(r1,r2); //运算两个中级节点,产生终结点 Expression<Func<int, int, int, int, int>> lambda = Expression.Lambda<Func<int, int, int, int, int>>(result,a,b,c,d); Console.WriteLine(lambda + ""); //输出‘(i,j,w,x)=>((i*j)+(w*x))’,z对应参数b,p对应参数a Func<int, int, int, int, int> f= lambda.Compile(); //将表达式树描述的lambda表达式,编译为可执行代码,并生成该lambda表达式的委托; Console.WriteLine(f(, , , ) + ""); //输出结果2
Console.ReadKey();
}

以上代码构成的Lambda表达式树如下图:

二、常见的一些表达式树用法

ConstantExpression :表示具有常量值的表达式

我们构建一个控制台应用程序

ConstantExpression _constExp = Expression.Constant("aaa",typeof(string));//一个常量
//Console.Writeline("aaa");
MethodCallExpression _methodCallexp=Expression.Call(typeof(Console).GetMethod("WriteLine",new Type[]{typeof(string)}),_constExp);
Expression<Action> consoleLambdaExp = Expression.Lambda<Action>(_methodCallexp);
consoleLambdaExp.Compile()();
Console.ReadLine();

输出一个常量,看一下结果

ParameterExpression :表示一个参数表达式

ParameterExpression _parameExp = Expression.Parameter(typeof(string), "MyParameter");
MethodCallExpression _methodCallexpP = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), _parameExp);
Expression<Action<string>> _consStringExp = Expression.Lambda<Action<string>>(_methodCallexpP, _parameExp);
_consStringExp.Compile()("Hello!!");

输出结果:

MethodCallExpression调用静态方法

我们建一个返回string的静态方法,传入一个object类型的值

public static string ConsStr(object str)
{
string _str = str + "aa";
Console.WriteLine(_str);
return _str;
}
ParameterExpression _paraObj = Expression.Parameter(typeof(object), "objPara");
MethodCallExpression _MyStateMethod = Expression.Call(typeof(Program).GetMethod("ConsStr", new Type[] { typeof(object) }), _paraObj);
Expression<Func<object, string>> _meyLambdaState = Expression.Lambda<Func<object, string>>(_MyStateMethod, _paraObj);
string s_tr = _meyLambdaState.Compile()("ni Hao");
Console.WriteLine("返回值: " + s_tr);

输出结果:

 

MethodCallExpression调用实例方法

我们写一个非静态方法

public string ConsStr2(object str)
{
string _str = str + "aa";
Console.WriteLine(_str);
return _str;
}

Expression.Call为我们提供了我们想要的重载:

Program _pg = new Program();
ParameterExpression _paraObj2 = Expression.Parameter(typeof(object), "objPara");
MethodCallExpression _MyStateMethod2 = Expression.Call(Expression.Constant(_pg), typeof(Program).GetMethod("ConsStr2"), _paraObj2);
Expression<Func<object, string>> _meyLambdaState2 = Expression.Lambda<Func<object, string>>(_MyStateMethod2, _paraObj2);
string s_tr2 = _meyLambdaState.Compile()("you shi ni ");
Console.WriteLine("返回值: " + s_tr2);

输出结果:

UnaryExpression:一元运算符表达式

用UnaryExpression做一个5--的表达式:

ConstantExpression _consNum = Expression.Constant(, typeof(int));
UnaryExpression _unaryPlus = Expression.Decrement(_consNum);
Expression<Func<int>> _unaryLam = Expression.Lambda<Func<int>>(_unaryPlus);
Console.WriteLine(_unaryLam.Compile()());

输出结果:

BinaryExpression : 二元运算符表达式

BinaryExpression  我们做一个a+b的例子

ParameterExpression _ParaA = Expression.Parameter(typeof(int), "a");
ParameterExpression _ParaB = Expression.Parameter(typeof(int), "b");
BinaryExpression _BinaAdd = Expression.Add(_ParaA, _ParaB);
Expression<Func<int, int, int>> _MyBinaryAddLamb = Expression.Lambda<Func<int, int, int>>(_BinaAdd, new ParameterExpression[] { _ParaA, _ParaB });
Console.WriteLine("表达式: "+ _MyBinaryAddLamb);
Console.WriteLine(_MyBinaryAddLamb.Compile()(, ));

输出结果:

两个表达式也可以放在一起:(a+b)*(--c)

ParameterExpression _ParaA = Expression.Parameter(typeof(int), "a");
ParameterExpression _ParaB = Expression.Parameter(typeof(int), "b");
BinaryExpression _BinaAdd = Expression.Add(_ParaA, _ParaB); //a+b
ParameterExpression _paraC = Expression.Parameter(typeof(int), "c");
UnaryExpression _paraDecr = Expression.Decrement(_paraC); //(a+b)*(--c)
BinaryExpression _binaMultiply = Expression.Multiply(_BinaAdd, _paraDecr);
Expression<Func<int, int, int, int>> _MyBinaryLamb = Expression.Lambda<Func<int, int, int, int>>(_binaMultiply, new ParameterExpression[] { _ParaA, _ParaB, _paraC });
Console.WriteLine("表达式: "+ _MyBinaryLamb);
Console.WriteLine(_MyBinaryLamb.Compile()(, , ));

输出结果:

三、使用表达式树访问属性

表达式树可以替换反射,但是未必性能就好,要实际测试一下,另外注意Compile调用过程涉及动态代码生成,所以出于性能考虑最好缓存一下生成的表达式树

接下来用Expression Tree的方式完成属性赋值和取值的操作,它们实现在如下两个静态方法中:CreateGetPropertyValueFunc和CreateSetPropertyValueAction。下面是CreateGetPropertyValueFunc的定义,它返回的是一个Func<object.object>委托:

 public static Func<object, object> CreateGetPropertyValueFunc()
{
var property = typeof(IFoo).GetProperty("Bar");
var target = Expression.Parameter(typeof(object));
var castTarget = Expression.Convert(target, typeof(IFoo));
var getPropertyValue = Expression.Property(castTarget, property);
var castPropertyvalue = Expression.Convert(getPropertyValue, typeof(object));
return Expression.Lambda<Func<object, object>>(castPropertyvalue , target).Compile();
}

下面是CreateSetPropertyValueAction方法,返回一个Action<object.object>委托:

 public static Action<object, object> CreateSetPropertyValueAction()
{
var property = typeof(IFoo).GetProperty("Bar");
var target = Expression.Parameter(typeof(object));
var propertyValue = Expression.Parameter(typeof(object));
var castTarget = Expression.Convert(target, typeof(IFoo));
var castPropertyValue = Expression.Convert(propertyValue, property.PropertyType);
var setPropertyValue = Expression.Call(castTarget, property.GetSetMethod(), castPropertyValue);
return Expression.Lambda<Action<object, object>>(setPropertyValue, target, propertyValue).Compile();
}

注:表达式树的水很深,此处只是入门,以后仍需继续研究使用~

C#秘密武器之表达式树的更多相关文章

  1. C#动态构建表达式树(三)——表达式的组合

    C#动态构建表达式树(三)--表达式的组合 前言 在筛选数据的过程中,可能会有这样的情况:有一些查询条件是公共的,但是根据具体的传入参数可能需要再额外增加一个条件.对于这种问题一般有两种方法: a. ...

  2. TypeScript: Angular 2 的秘密武器(译)

    本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch?v=e3djIqAGqZo 开场白 开场白主要分为三部分: 感谢了 ...

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

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

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

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

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

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

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

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

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

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

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

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

  9. 干货!表达式树解析"框架"(1)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 关于我和表达式树 其实我也没有深入了解表达式树一些内在实现的原理 ...

随机推荐

  1. POJ2912 Rochambeau [扩展域并查集]

    题目传送门 Rochambeau Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4463   Accepted: 1545 ...

  2. 【搜索】bzoj3109 [cqoi2013]新数独

    搜索,没什么好说的.要注意读入. Code: #include<cstdio> #include<cstdlib> using namespace std; ][]= {{,, ...

  3. 【动态规划去除冗余】NOIP2010-乌龟棋

    [题目大意] [思路] 最简单的思路是五维数组,但是当前走到的步数由已经取到的卡片决定,所以只需要四维.本来想要改一个滚动数组的,但是好像没有滚起来,算了(ノ`Д)ノ. 在学校要晚自习到21:15,回 ...

  4. bzoj 4627: [BeiJing2016]回转寿司

    4627: [BeiJing2016]回转寿司 Description 酷爱日料的小Z经常光顾学校东门外的回转寿司店.在这里,一盘盘寿司通过传送带依次呈现在小Z眼前.不同的寿 司带给小Z的味觉感受是不 ...

  5. iOS 带箭头菜单选项弹窗LFPopupMenu

    一.效果图 由于是模拟器缩得比较小,一些细线可能显示不出来,不是bug哈. 二.用法 LFPopupMenuItem *item1 = [LFPopupMenuItem createWithTitle ...

  6. Linux PHP 编译参数详解(二)

    对于喜欢玩开源软件的童鞋么,都喜欢自己编译安装程序,本文说明下如何编译安装php的详细参数. 示例: ./configure \ --prefix=/usr/local/php --with-zlib ...

  7. 乐观锁悲观锁对应的JAVA代码和数据库

    乐观锁悲观锁是一种思想.可以用在很多方面. 比如数据库方面.悲观锁就是for update乐观锁就是 version字段 JDK方面:悲观锁就是sync乐观锁就是原子类(内部使用CAS实现) 本质来说 ...

  8. iOS开发利器-CocoaPods安装和使用教程

    新博客http://www.liuchendi.com 开发iOS项目时肯定会用到许多第三方项目,比如说:ASIHttprequest,JSONKit等等,一些类库可能又关联着其他类库,如果超过一定的 ...

  9. KEIL、uVision、RealView、MDK、KEIL C51之间比较

    KEIL uVision,KEIL MDK,KEIL For ARM,RealView MDK,KEIL C51,KEIL C166,KEIL C251 从接触MCS-51单片机开始,我们就知道有一个 ...

  10. ALCHEMY 2 (FLASCC)新手入门 (WINDOWS 版)

    Adobe Alchemy(炼金术) 2的预发布版本已经对开发者开放,并且已经更名为 FlasCC.炼金术简单来说就是把c/c 代码编译成swf文件,它吸收了c/c 高效的执行效率,比传统开发的swf ...