表达式树可使用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. Mosquitto-MQTT

    安装Mosquitto #To use the new repository you should first import the repository package signing key: w ...

  2. Xamarin Mono错误: unable to find explicit activity class

    unable to find explicit activity class在android开发很常见,网上一般是java的解决办法,对我们这些xamariner就无语了. xamarin中用attr ...

  3. Hibernate如何一个类映射两个表

    一个User类有username,password属性,还有 otherInformation等其他属性,username和password映射到一个表,otherInformation等其他属性映射 ...

  4. 【POJ】1035 Spell checker

    字典树. #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib ...

  5. 【转】onPrepareOptionsMenu 和onCreateOptionsMenu 的区别

    原文网址:http://blog.csdn.net/allenjy123/article/details/7467084 @Override public boolean onCreateOption ...

  6. 数据结构(线段树):CodeForces 145E Lucky Queries

    E. Lucky Queries time limit per test 3 seconds memory limit per test 256 megabytes input standard in ...

  7. 【有源汇上下界费用流】BZOJ 3876 [Ahoi2014]支线剧情

    题目链接: http://www.lydsy.com:808/JudgeOnline/problem.php?id=3876 题目大意: 给定一张拓扑图(有向无环图),每条边有边权,每次只能从第一个点 ...

  8. Sqrt(x)——LeetCode

    Implement int sqrt(int x). Compute and return the square root of x. 题目大意:实现求一个int的根. 解题思路:二分. public ...

  9. [转]浏览器如何和Web服务器通信

    http://hi.baidu.com/ywqme/item/b5297014b2e58f4e6826bb74 概述 普通网民打开网页,访问网站,并不需要了解所谓HTTP协议.作为软件工程师,了解一下 ...

  10. poj 3903 最长上升子序列 Stock Exchange

    题目链接:http://poj.org/problem?id=3903 #include <cstdio> #include <cmath> #include <algo ...