表达式:使用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 < ...
随机推荐
- Node.js事件循环
Node JS是单线程应用程序,但它通过事件和回调概念,支持并发. 由于Node JS每一个API是异步的,作为一个单独的线程,它使用异步函数调用,以保持并发性.Node JS使用观察者模式.Node ...
- Firebase能改变什么(对SaaS,BaaS,PaaS,IaaS的解释比较清楚)
作为Google Cloud对标Amazon AWS重要的一环,Firebase能改变什么? 雷锋网 2016-05-25 12:18:49 查看源网址 阅读数:12 按:本文作者刘之,野狗CEO.野 ...
- npm check failed 解决办法
npm ERR! shasum check failed for C:\Users\MM\AppData\Local\Temp\npm-10900-415697c8\registry.npmjs.or ...
- 【HDOJ】2425 Hiking Trip
优先级队列+BFS. #include <iostream> #include <cstdio> #include <cstring> #include <q ...
- 实战weblogic集群之应用部署
一.创建应用发布目录,上传应用包. 1.在10.70.52.11-14的/app/sinova目录下建立applications目录(名称可以自定义),作为我们应用的发布目录. $ mkdir /ap ...
- (转载)URL与URI的区别
(转载)http://blog.csdn.net/eagle51998/article/details/372052 1 URL(Uniform Resoure Locator:统一资源定位器)是W ...
- 数据结构(树链剖分,线段树):SDOI 2016 游戏
4515: [Sdoi2016]游戏 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 351 Solved: 157[Submit][Status][ ...
- RAM——[HAOI2007]理想的正方形
题目:[HAOI2007]理想的正方形 描述: [问题描述] 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. [输入]: 第一行为3个 ...
- Spring与Hibernate集成中的Session问题
主要讨论Spring与Hibernate集成中的session问题 1.通过getSession()方法获得session进行操作 public class Test extends Hibernat ...
- Apache-Tika解析Excell文档
通常在使用爬虫时,爬取到网上的文章都是各式各样的格式处理起来比较麻烦,这里我们使用Apache-Tika来处理Excell格式的文章,如下: package com.mengyao.tika.app; ...