看下面2行代码:
Func<int, int, int> func = (m, n) => m * n + 2; //匿名方法 Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;//用快捷方式(就是用lambda)声明一个表达式目录树
第一行是用lambda表达式表明了一个委托,第二行代码则是声明了一个表达式目录树,左边代码虽然看着一样,但是其实是不一样的。使用ExpressionTreeVisualizer工具查看exp会发现这里和上面的委托是完全不一样的,这里面将变量和常量等都做了解析。它类似于一个树形结构,描述不同变量和常量之间的关系,是一种数据结构
更具体形象一点可以看下图,将其层层解析出来:
通过上面我们可以知道一个委托和表达式目录树都可以通过一个lambda表达式来表示,但是却不是一种东西,但是,委托和表达式目录树是可以进行转换的。
int iResult1 = func.Invoke(12, 23); //exp.Compile()=> 委托; int iResult2 = exp.Compile().Invoke(12, 23); //12 * 23 +2 278
看上面代码,通过compile方法可以转换成委托。
还有一点需要注意,用lambda表达式声明表达式目录树的时候不能有语句体(就是{}),只能有一行代码:
Expression<Func<int, int, int>> exp1 = (m, n) => { return m * n + 2; };
上面的代码就是错误的,需要改成:
Expression<Func<int, int, int>> exp1 = (m, n) => m * n + 2;
手动拼装表达式目录树
先插一句,如果需要将现有的通过lambda形式声明出来的表达式目录树换成手动拼装的,而且本身对其不怎么熟悉的话可以通过反编译工具查看编译工具中c#语言对应的表达式目录树写法。很有用
示例1 先看一个非常简单的:
Expression<Func<int>> expression = () => 123 + 234;
现在我们不使用lambda表达式来声明表达式目录树了,我们手动拼装:
//手动拼装表达式目录树,不是用的lambda的快捷方式 { //Expression<Func<int>> expression = () => 123 + 234; //ConstantExpression表示具有常数值的表达式, ConstantExpression left = Expression.Constant(123, typeof(int)); //也可以这样写,第二个参数不必写 //ConstantExpression left = Expression.Constant(123); ConstantExpression right = Expression.Constant(234, typeof(int)); //Add表示加,如果是乘的话就要用Multiply var plus = Expression.Add(left, right); //完成拼装 Expression<Func<int>> expression = Expression.Lambda<Func<int>>(plus, new ParameterExpression[0]); //转换成委托并执行 int iResult = expression.Compile().Invoke(); int iResult1 = expression.Compile()(); }
示例2 下面看一个稍微复杂一点的:
// 更复杂一点的: Expression<Func<int, int, int>> expression = (m, n) => m * n + m + n + 2;
手动拼装:
// 更复杂一点的: //Expression<Func<int, int, int>> expression = (m, n) => m * n + m + n + 2; //声明变量 ParameterExpression m = Expression.Parameter(typeof(int), "m"); ParameterExpression n = Expression.Parameter(typeof(int), "n"); //常量2 ConstantExpression constant2 = Expression.Constant(2, typeof(int)); var multiply = Expression.Multiply(m, n); var plus1 = Expression.Add(multiply, m); var plus2 = Expression.Add(plus1, n); var plus = Expression.Add(plus2, constant2); Expression<Func<int, int, int>> expression = Expression.Lambda<Func<int, int, int>>(plus, new ParameterExpression[] { m, n }); int iResult = expression.Compile().Invoke(12, 10); }
示例3:
Expression<Func<People, bool>> lambda = (x) => x.Id.ToString().Equals("5");
手动拼装:
飒