C#表达式内部结构



我正在努力了解Expression类是如何工作的。

一个简单的例子:

Expression<Func<string, bool>> exp = p => p.Contains("x");

为什么我没有得到像";无法转换为表达式<Func<字符串,bool>gt;因为它不是委托?

我试着调试这个代码,VS将我转移到这个方法

public static ParameterExpression Parameter(Type type, string name)
{
Validate(type, allowByRef: true);
bool byref = type.IsByRef;
if (byref)
{
type = type.GetElementType();
}
return ParameterExpression.Make(type, name, byref);
}

这是微软的魔法吗?我没有找到任何重写转换器或其他东西,谁调用了参数方法?他们是否在编译器中编写了一些特殊代码来编译Expression类,而不是像任何其他";标准";班

是的,你可以称之为魔术,因为编译器会在幕后为你做很多提升。让我们看看最简单的程序会发生什么。我刚刚创建了一个控制台应用程序并添加了您的代码。

internal class Program {
private static void Main(string[] args) {
Expression<Func<string, bool>> exp = p => p.Contains("x");
}
}

我编译了它并查看了IL代码。(如果你喜欢,可以跳过这一部分(

IL_0000: ldtoken      [mscorlib/*23000001*/]System.String/*01000021*/
IL_0005: call         class [mscorlib/*23000001*/]System.Type/*01000014*/ [mscorlib/*23000001*/]System.Type/*01000014*/::GetTypeFromHandle(valuetype [mscorlib/*23000001*/]System.RuntimeTypeHandle/*01000022*/)/*0A000014*/
IL_000a: ldstr        "p"
IL_000f: call         class [System.Core/*23000002*/]System.Linq.Expressions.ParameterExpression/*0100001D*/ [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/::Parameter(class [mscorlib/*23000001*/]System.Type/*01000014*/, string)/*0A000040*/
IL_0014: stloc.0      // V_0
IL_0015: ldloc.0      // V_0
IL_0016: ldtoken      method instance bool [mscorlib/*23000001*/]System.String/*01000021*/::Contains(string)/*0A000041*/
IL_001b: call         class [mscorlib/*23000001*/]System.Reflection.MethodBase/*0100002E*/ [mscorlib/*23000001*/]System.Reflection.MethodBase/*0100002E*/::GetMethodFromHandle(valuetype [mscorlib/*23000001*/]System.RuntimeMethodHandle/*0100002F*/)/*0A000042*/
IL_0020: castclass    [mscorlib/*23000001*/]System.Reflection.MethodInfo/*01000017*/
IL_0025: ldc.i4.1
IL_0026: newarr       [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/
IL_002b: dup
IL_002c: ldc.i4.0
IL_002d: ldstr        "x"
IL_0032: ldtoken      [mscorlib/*23000001*/]System.String/*01000021*/
IL_0037: call         class [mscorlib/*23000001*/]System.Type/*01000014*/ [mscorlib/*23000001*/]System.Type/*01000014*/::GetTypeFromHandle(valuetype [mscorlib/*23000001*/]System.RuntimeTypeHandle/*01000022*/)/*0A000014*/
IL_003c: call         class [System.Core/*23000002*/]System.Linq.Expressions.ConstantExpression/*01000030*/ [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/::Constant(object, class [mscorlib/*23000001*/]System.Type/*01000014*/)/*0A000043*/
IL_0041: stelem.ref
IL_0042: call         class [System.Core/*23000002*/]System.Linq.Expressions.MethodCallExpression/*01000031*/ [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/::Call(class [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/, class [mscorlib/*23000001*/]System.Reflection.MethodInfo/*01000017*/, class [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/[])/*0A000044*/
IL_0047: ldc.i4.1
IL_0048: newarr       [System.Core/*23000002*/]System.Linq.Expressions.ParameterExpression/*0100001D*/
IL_004d: dup
IL_004e: ldc.i4.0
IL_004f: ldloc.0      // V_0
IL_0050: stelem.ref
IL_0051: call         class [System.Core/*23000002*/]System.Linq.Expressions.Expression`1/*01000032*/<!!0/*class [mscorlib*//*23000001*//*]System.Func`2*//*01000012*//*<string, bool>*/> [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/::Lambda<class [mscorlib/*23000001*/]System.Func`2/*01000012*/<string, bool>>(class [System.Core/*23000002*/]System.Linq.Expressions.Expression/*0100002D*/, class [System.Core/*23000002*/]System.Linq.Expressions.ParameterExpression/*0100001D*/[])/*2B000002*/
IL_0056: pop

这个IL代码大致翻译为

// Define Expresin parameter p
var parameterExpression = Expression.Parameter(typeof (string), "p");
// Gets method handler for string.Contains method
// Plase note that __methodref can not be used in c# butit is valid in il code
var methodInfo = (MethodInfo) MethodBase.GetMethodFromHandle(__methodref (string.Contains));
// Constant string x added as paramter
var constantXString = new Expression[] {Expression.Constant("x", typeof (string))};
// Call given method on the the given parameter and make it into a lambda expression
Expression.Lambda<Func<string, bool>>(Expression.Call(parameterExpression, methodInfo, constantXString), parameterExpression);

这是代码的第一行,您可以看到正在调用public static ParameterExpression Parameter(Type type, string name)

最新更新