关于 .net expression tree

Only expression trees that represent lambda expressions can be executed. Expression trees that represent lambda expressions are of type LambdaExpression or Expression<TDelegate>. To execute these expression trees, call the Compile method to create an executable delegate, and then invoke the delegate.

If the type of the delegate is not known, that is, the lambda expression is of type LambdaExpression and not Expression<TDelegate>, you must call the DynamicInvoke method on the delegate instead of invoking it directly.

If an expression tree does not represent a lambda expression, you can create a new lambda expression that has the original expression tree as its body, by calling the Lambda<TDelegate>(Expression, IEnumerable<ParameterExpression>) method. Then, you can execute the lambda expression as described earlier in this section.

只有LambdaExpression是可执行了,一个Expression仅仅是一个“表示”,一种普通结构,它本身并不是“可执行的”。不过,可以根据Expression来创建委托(LambdaExpress或Func<>来表示),从而“可执行”。

 

Func<T1, string> f = m => m.Name;  //生成的IL为创建一个Func<T1, string>的委托

Expression<Func<T1, string>> ff = m => m.Name; //就不一样了,Console.WriteLine(ff is LambdaExpression) 输出 true,神奇。Why?来看下生成的IL

.entrypoint
// 代码大小       78 (0x4e)
.maxstack  5
.locals init ([0] class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Func`2<class ClassLibrary1.T1,string>> fff,
         [1] class [System.Core]System.Linq.Expressions.ParameterExpression V_1)
IL_0000:  nop
IL_0001:  ldtoken    ClassLibrary1.T1
IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000b:  ldstr      "m"
IL_0010:  call       class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type,string)
IL_0015:  stloc.1
IL_0016:  ldloc.1
IL_0017:  ldtoken    method instance string ClassLibrary1.T1::get_Name()
IL_001c:  call       class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
IL_0021:  castclass  [mscorlib]System.Reflection.MethodInfo
IL_0026:  call       class [System.Core]System.Linq.Expressions.MemberExpression [System.Core]System.Linq.Expressions.Expression::Property(class [System.Core]System.Linq.Expressions.Expression,class [mscorlib]System.Reflection.MethodInfo)
IL_002b:  ldc.i4.1
IL_002c:  newarr     [System.Core]System.Linq.Expressions.ParameterExpression
IL_0031:  dup
IL_0032:  ldc.i4.0
IL_0033:  ldloc.1
IL_0034:  stelem.ref
IL_0035:  call       class [System.Core]System.Linq.Expressions.Expression`1<!!0> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Func`2<class ClassLibrary1.T1,string>>(class [System.Core]System.Linq.Expressions.Expression,class [System.Core]System.Linq.Expressions.ParameterExpression[])
IL_003a:  stloc.0
IL_003b:  ldloc.0
IL_003c:  callvirt   instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
IL_0041:  call       void [mscorlib]System.Console::WriteLine(object)
IL_0046:  nop
IL_0047:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_004c:  pop
IL_004d:  ret

看了IL之后就清楚了:编译器帮忙生成了创建Expression Tree的代码,最终使用Expression.Lambda()方法创建了LambdaExpression的实例。难怪 Expression<Func<T1, string>> is LambdaExpression。

 

那如果以后,某天创建某个表达式树的代码不会写了,是不是可以直接用C#代码写出最终结果,让编译器帮我们生成IL后再翻译成C#代码?偷偷乐一个先…

 

 

发表评论

电子邮件地址不会被公开。