表达式:使用API创建表达式树(1)
表达式树可使用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)的更多相关文章
- 表达式:使用API创建表达式树(3)
一.DebugInfoExpression:发出或清除调试信息的序列点. 这允许调试器在调试时突出显示正确的源代码. static void Main(string[] args) { var asm ...
- 表达式:使用API创建表达式树(2)
一.BlockExpression类:表式一个包含可在其中定义变量的表达式序列的块.是一组表达式,类似于多个委托的 += 后的效果,其返回表达式是最后一个表达式决定.以下是BlockExpressio ...
- 表达式:使用API创建表达式树(6)
一.ConstantExpression:表示具有常量值的表达式.因为表达式应用过程中,参数据多是 Expressions 类型,算是对常量值的一种包装吧. ConstantExpression使用比 ...
- 表达式:使用API创建表达式树(5)
一.ConditionalExpression:表达式 生成如 IIF((a == b), "a和b相等", "a与b不相等") 式子. 使用: Paramet ...
- 表达式:使用API创建表达式树(4)DynamicExpression
DynamicExpression:表示动态操作.这个网上可见的资料少得可怜,但想到MVC和第三方的动态语言能在NET运行.好奇的倒腾了下 先声明两个类(有相同的方法和字段,但不是继承于同一接口的类) ...
- EF4.0、4.3创建表达式树状动态查询总结
---------------------------------------------快速适用 效果: where name like '%王%' and Age>=35 or Age< ...
- 【C#表达式树 五】工厂模式创建表达式树节点
常量 1.值常量 (p)=>100+88+p ParameterExpression par = Expression.Parameter(typeof(int), "p" ...
- [C# Expression] 之动态创建表达式
上一篇中说到了 Expression 的一些概念性东西,其实也是为了这一篇做知识准备.为了实现 EFCore 的多条件.连表查询,简化查询代码编写,也就有了这篇文章. 在一些管理后台中,对数据进行 ...
- NX二次开发-NX11创建表达式组NXOpen::ExpressionGroup
NX11+VS2013 #include <uf.h> #include <uf_modl.h> #include <uf_part.h> #include < ...
随机推荐
- 将Excel导入到数据中
常用的方式的有两种: 1. 通过 Microsoft.Jet.OLEDB.4.0 或 Microsoft.ACE.OLEDB.12.0 Microsoft.ACE.OLEDB.12.0 需要安装 A ...
- 转:Ubuntu12.04 LTS 使用心得-开机挂载其他分区
1.在/media目录下创建好用来关联你要挂载的分区的文件夹(相当于一个虚拟目录/挂载点,链接/映射到你要挂载的盘符去) 我要挂载4个分区,所以创建了四个挂载点,名字随便取,只要你自己认的出来哪个对应 ...
- jQuery折叠风琴
这个效果用jQuery做是很方便的,根本不需要搞得很复杂. 网上有些效果DEMO不仅用了jQuery还引用一两个封装文件,真是匪夷所思. 最初想到了toggle: jQuery(document).r ...
- 【转】Usage of sendBroadcast()
原文网址:http://stackoverflow.com/questions/4883079/usage-of-sendbroadcast sendBroadcast() - Should it b ...
- 【转】 Linux/Unix 进程间通信的各种方式及其比较
http://blog.csdn.net/guopengzhang/article/details/5528260 进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问 ...
- python 代码格式化工具:YAPF
学习资料: https://github.com/google/yapf 背景 现在的大多数 Python 代码格式化工具(比如:autopep8 和 pep8ify)是可以移除代码中的 lint 错 ...
- 在eclipse下编译hadoop2.0源码
Hadoop是一个分布式系统基础架构,由apache基金会维护并更新.官网地址: http://hadoop.apache.org/ Hadoop项目主要包括以下4个模块: Hadoop Common ...
- 赵雅智_ListView_BaseAdapter
Android界面中有时候须要显示略微复杂的界面时,就须要我们自己定义一个adapter,而此adapter就要继承BaseAdapter,又一次当中的方法. Android中Adapter类事实上就 ...
- OpenCV 编码样式指南
OpenCV 编码样式指南 前言 本文档是对OpenCV中代码风格的简短说明,因为OpenCV的核心库(cv,cvaux)是用C和C++编写的,所以本文档仅对用C和C++代码的编写有效. 文件 ...
- J2EE之WebLogic Server
WebLogic是用于开发.集成.部署和管理大型分布式Web应用. 网络应用和数据库应 用的Java应用server. 将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用 ...