表达式树可使用Expressions类的静态工厂方法来创建。这种用API的方式创建给予我们在编程极大的灵活性,MSDN上关于表达式的例子也不少,但在使用过程中还是会遇到许多麻烦,对有的表达式类,介绍得不是太清楚。这里把一些常见的表达示类的使用整理了下。
 
BinaryExpression类: 是表示包含二元运算符的表达式。

  比如构建形如 (100+88)是个典型的 a+b 式的二元计算,表达式代码如下

BinaryExpression binaryexp = Expression.MakeBinary
(ExpressionType.Add, Expression.Constant(), Expression.Constant());
Console.WriteLine(Expression.Lambda(binaryexp).Compile().DynamicInvoke());

输出: 188

MakeBinary是在Expressions中定义的一个静态工厂方法(根据ExpressionType来选择调用),最终调用的是Expression.Add 静态方法
所以是与下面操作等效的

BinaryExpression binaryexp = Expression.Add(Expression.Constant(), Expression.Constant());

a+b的值类型的操作比较简单,但如果是 "100"+"88" 呢,改下上面的操作

BinaryExpression binaryexp = Expression.Add(Expression.Constant(""), Expression.Constant(""));
Console.WriteLine(Expression.Lambda(binaryexp).Compile().DynamicInvoke());

但这时会报错 “没有为类型“System.String”和“System.String”定义二进制运算符 Add”,这是怎么回事,在我们代码时如果写 string s= "100"+"88";是没错的啊。实际上字串的 +  在生成IL代码时,会转换成 string 的 Concat 扩展方法来操作。因此要实现如  "100"+"88" 还是稍显麻烦

第一步:获取Concat方法的MethodInfo

MethodInfo mif = typeof(string).GetMethods().First(m => m.Name == "Concat" && m.GetParameters().Length ==2);
    因为Concat的参数是可变的方法参数,获取MethodInfo,一定要加上m.GetParameters().Length=实际调用时的参数个数据,不然会出现参数不匹配错误。

第二步:使用MakeBinary的另一个重载方法

    BinaryExpression binaryexp = Expression.Add(Expression.Constant(""), Expression.Constant(""), mif);
Console.WriteLine(Expression.Lambda(binaryexp).Compile().DynamicInvoke());

输出: 10088

回头再看 Expression.Add 的实现

 if (!(method == (MethodInfo) null))
return Expression.GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true);
if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type))
return (BinaryExpression) new SimpleBinaryExpression(ExpressionType.Add, left, right, left.Type);
else
return Expression.GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true);

从中看出,当参数年method为null 时,实际上要检查 TypeUtils.IsArithmetic(left.Type),而IsArithmetic的定义为

  internal static bool IsArithmetic(Type type)
{
type = TypeUtils.GetNonNullableType(type);
if (!type.IsEnum)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
return true;
}
}
return false;
}

所以Expression.Add(Expression.Constant("100"), Expression.Constant("88"))在不给定操作方法时,会报错。当指定操作方法时,表达式虽然用tostring 是  "100"+"88" ,但调用的操作方法是 string.Concat。就象用方法表达式一样

MethodCallExpression methExp = Expression.Call(mif, Expression.Constant("100"), Expression.Constant("88"));

因此在调用  Expression.Lambda(binaryexp).Compile().DynamicInvoke();和 Expression.Lambda(methExp).Compile().DynamicInvoke();的结果是一样的

另外从 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) 前部分看,Add方法是要求类型完全相同,在看上去可行的表达式 Expression.Add(Expression.Constant(100), Expression.Constant(88.0)) (后面是Double类型 ),也会报错。而就当改为
 Expression.Add(Expression.Constant((Double)100), Expression.Constant(88.0)) 或 Expression.Add(Expression.Constant(100.0), Expression.Constant(88.0)) 。

表达式:使用API创建表达式树(1)的更多相关文章

  1. 表达式:使用API创建表达式树(3)

    一.DebugInfoExpression:发出或清除调试信息的序列点. 这允许调试器在调试时突出显示正确的源代码. static void Main(string[] args) { var asm ...

  2. 表达式:使用API创建表达式树(2)

    一.BlockExpression类:表式一个包含可在其中定义变量的表达式序列的块.是一组表达式,类似于多个委托的 += 后的效果,其返回表达式是最后一个表达式决定.以下是BlockExpressio ...

  3. 表达式:使用API创建表达式树(6)

    一.ConstantExpression:表示具有常量值的表达式.因为表达式应用过程中,参数据多是 Expressions 类型,算是对常量值的一种包装吧. ConstantExpression使用比 ...

  4. 表达式:使用API创建表达式树(5)

    一.ConditionalExpression:表达式 生成如 IIF((a == b), "a和b相等", "a与b不相等") 式子. 使用: Paramet ...

  5. 表达式:使用API创建表达式树(4)DynamicExpression

    DynamicExpression:表示动态操作.这个网上可见的资料少得可怜,但想到MVC和第三方的动态语言能在NET运行.好奇的倒腾了下 先声明两个类(有相同的方法和字段,但不是继承于同一接口的类) ...

  6. EF4.0、4.3创建表达式树状动态查询总结

    ---------------------------------------------快速适用 效果: where name like '%王%' and Age>=35 or Age< ...

  7. 【C#表达式树 五】工厂模式创建表达式树节点

    常量 1.值常量  (p)=>100+88+p ParameterExpression par = Expression.Parameter(typeof(int), "p" ...

  8. [C# Expression] 之动态创建表达式

    上一篇中说到了 Expression 的一些概念性东西,其实也是为了这一篇做知识准备.为了实现 EFCore 的多条件.连表查询,简化查询代码编写,也就有了这篇文章.   在一些管理后台中,对数据进行 ...

  9. NX二次开发-NX11创建表达式组NXOpen::ExpressionGroup

    NX11+VS2013 #include <uf.h> #include <uf_modl.h> #include <uf_part.h> #include < ...

随机推荐

  1. js/bat批处理调用谷歌浏览器chrome批量打开网页测试web性能

    批处理批量打开网页 其实用java就可以搞定,但是这么一个轻巧的测试,js或者bat批处理去一次性打开几百个网页测试一下页面没必要上java 两者的区别,js的话,只能打开多个浏览器实例,不方便查看效 ...

  2. Frame Stacking

    poj1128:http://poj.org/problem?id=1128 题意:一个二维图里面有几个相框(四条边的空心矩形框).有重叠,求重叠顺序.还有题目保证至少存在一种符合要求的序列,当有多种 ...

  3. iostat 使用说明

    LINUX [oracle@perass back]$ iostat -m 1 10 Linux 2.6.18-194.el5 (perass) 03/01/2014 avg-cpu: %user % ...

  4. 源码安装Ansible

    一.Ansible介绍 ansible是一款的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置.批 ...

  5. 数据结构(并查集):COGS 260. [NOI2002] 银河英雄传说

    260. [NOI2002] 银河英雄传说 ★★☆   输入文件:galaxy.in   输出文件:galaxy.out   简单对比时间限制:5 s   内存限制:128 MB [问题描述] 公元五 ...

  6. 【宽搜】BAPC2014 J Jury Jeopardy (Codeforces GYM 100526)

    题目链接: http://codeforces.com/gym/100526 http://acm.hunnu.edu.cn/online/?action=problem&type=show& ...

  7. 关于TCP的粘包和拆包

    问题产生 一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和封包问题. 下面可以看一张图,是客户端向服务端发送包: 1. 第一种情况 ...

  8. android webview无法加载网页

    主要原因是没有在AndroidManifest.xml里面设置如下: <user-permission android:name="android.permission.INTERNE ...

  9. 【模拟赛】BYVoid魔兽世界模拟赛 解题报告

    题目名称(点击进入相关题解) 血色先锋军 灵魂分流药剂 地铁重组 埃雷萨拉斯寻宝 源文件名(.c/.cpp/.pas) scarlet soultap subway eldrethalas 输入文件名 ...

  10. C#中的 IList, ICollection ,IEnumerable 和 IEnumerator

    IList, ICollection ,IEnumerable 很显然,这些都是集合接口的定义,先看看定义: // 摘要: // 表示可按照索引单独访问的对象的非泛型集合. [ComVisible(t ...