【问题标题】:How to call the method from a MethodCallExpression in c#如何从 C# 中的 MethodCallExpression 调用方法
【发布时间】:2010-10-21 01:24:22
【问题描述】:

我有一个方法调用表达式并尝试调用该方法。我想出了一个办法,但我在检索参数值时遇到了问题,因为不是每个参数都用 ConstantExpression 描述。

Expression<Action<T>> = t => t.DoSomething(Par0, Par1, Par2);
MethodCallExpression methodCallExpression = selector.Body 
                                               as MethodCallExpression;

// get the information which is needed to invoke the method from the provided 
// lambda expression.
MethodInfo methodInfo = methodCallExpression.Method;
object[] arguments = methodCallExpression.Arguments.OfType<ConstantExpression>()
                            .Select(p => p.Value).ToArray();

// invoke the expression on every item within the enumerable
foreach (TSource item in source)
{ 
    methodInfo.Invoke(item, arguments);
}

此外,我还看到了一些其他调用该方法的方法,现在我不确定什么是正确的方法。

var func = expression.Compile();
var success = func.Invoke();

所以我的问题是,如何从methodCallExpression.Arguments 检索方法参数值?

或者有没有更简单的方法来实现我的目标?

【问题讨论】:

    标签: c# .net lambda parameters


    【解决方案1】:

    您无需担心自己检索参数和调用 MethodInfo,您可以让 .NET 为您完成。您需要做的就是创建一个包含该方法的 Lambda 表达式。

    例如。

    MethodCallExpression expression = GetExpressionSomeHow();
    object result = Expression.Lambda(expression).Compile().DynamicInvoke();
    

    这就是我在我的 Linq 提供程序中处理嵌套查询的方式。

    编辑:实际上,看起来您可能已经在选择器变量中有一个 LambdaExpression。在这种情况下,您应该能够直接编译和调用它:

    object result = selector.Compile().DynamicInvoke();
    

    【讨论】:

    • 谢谢,这样容易多了。我现在这样做:// 编译 lambda 表达式以获取用于调用的委托。 Action action = selector.Compile(); // 在可枚举的 foreach 中的每个项目上调用表达式(TSource item in source){ action(item);最后我还找到了这个问题的 msdn 文档:msdn.microsoft.com/en-us/library/bb882536.aspx
    • 你有什么理由不能只做selector.Compile()()?为什么在括号有效时使用InvokeDynamicInvoke
    【解决方案2】:

    编译表达式是一项非常密集的操作,因此只有在您计划重新使用该表达式时,我才会这样做。否则我会推荐反射方式;你会发现它执行得更快。切勿在紧密循环中调用 expression.Compile()。

    【讨论】:

      【解决方案3】:

      @Ch00k

      selector.Compile();
      

      给你一个委托。对于实例方法,您需要一个实例来调用此方法。您将此实例作为参数传递给 DynamicInvoke ala

      // Grab the method from MyClass - param1 and param2 are the actual parameters you
      // want to pass to the method call.
      Expression<Func<MyClass, TValue>> selector = (x => x.MyMethod(param1, param2));
      
      // Create an instance of MyClass to call the method on
      var myClass = new MyClass();
      
      // Call the method on myClass through DynamicInvoke
      object returnValue = selector.Compile().DynamicInvoke(myClass);
      

      【讨论】:

        【解决方案4】:

        如果您想将您的 expression.call 编译为 Action 或 Func,您可以这样做:

        var method = typeof(MyType).GetMethod(nameof(MyType.MyMethod), BindingFlags.Public | BindingFlags.Static);
        var parameter = Expression.Parameter(typeof(string), "s");
        var call = Expression.Call(method, parameter);
        var lambda = Expression.Lambda<Func<string, int>>(call, call.Arguments.OfType<ParameterExpression>());
        var func = lambda.Compile();
        int result = func("sample string input");
        

        这使您可以简单地执行 func.Invoke("mystring") 或 func("my string");

        这里的秘密是你需要传递你在创建 Expression.Call 时使用的相同参数,否则你会得到一个类型为“InvalidOperationException”的错误,类型为“System.String”的变量 's' 从范围''引用,但它没有定义。

        【讨论】:

          【解决方案5】:

          我会尝试这个来返回对象:

          private static object _getValue(MethodCallExpression expression)
          {
              var objectMember = Expression.Convert(expression, typeof(object));
          
              var getterLambda = Expression.Lambda<Func<object>>(objectMember);
          
              var getter = getterLambda.Compile();
          
              return getter();
          }
          

          调用以下命令会快很多:

          LambdaExpression l = Expression.Lambda(Expression.Convert(element, element.Type));
          return l.Compile().DynamicInvoke();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-07-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多