Expression.Lambda()的参数问题

And*_*ock 2 c# lambda

更新:这确实有效,我是愚蠢的:(

我有以下扩展方法

public static string ExtMethod(this object self, object myparameter);
Run Code Online (Sandbox Code Playgroud)

在运行时,这可以通过多种方式调用,我认为这些都是可能的:

Expression<Func<T, string>> expr = x => x.property.ExtMethod(5);
Expression<Func<T, string>> expr = x => x.property.ExtMethod(new object());
Expression<Func<T, string>> expr = x => x.property.ExtMethod(someMethod());
Expression<Func<T, string>> expr = x => x.property.ExtMethod(x.someMethod());
Expression<Func<T, string>> expr = x => x.property.ExtMethod(x.OtherProperty);
Run Code Online (Sandbox Code Playgroud)

我需要做的是评估" myparameter",给出" expr"和" T"

因为在两种情况下x使用myparameter,我认为我需要创建一个表单的委托:

Expression<Func<T, object>> expr = x => [myparameter expression here]
Run Code Online (Sandbox Code Playgroud)

我认为这会奏效:

var extMethodExpr = expr.Body as MethodCallExpression;
var myparameterExpr = extMethodExpr.Arguments[1];

var myparam = Expression.Lambda(myparameterExpr, expr.Parameters).Compile().Invoke(someT)
Run Code Online (Sandbox Code Playgroud)

但对于不涉及的表达式x,我得到TargetParameterCountException:(

在这些情况下,如果我这样做:

var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT)
Run Code Online (Sandbox Code Playgroud)

它工作正常.

我该如何解决这个问题?

谢谢

Mar*_*ell 6

好; 到了底部; 在线:

var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT);
Run Code Online (Sandbox Code Playgroud)

如果你没有尝试传入a someT,这将适用于那些不参与x参数的表达式; 对于那些做的,你需要告诉lambda包含参数(原始lambda中的相同参数) - 简单地通过:

var myparam = Expression.Lambda(myparameterExpr,
             outerLambda.Parameters[0]).Compile().Invoke(someT);
Run Code Online (Sandbox Code Playgroud)

这是一些评估内部参数的工作代码(给定参数类型的实例); 请注意,我使用参数即使它涉及x- 否则,它会对实例做什么?

using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo {
    public string Bar {get;set;}
    public int someMethod() { return 4; }
    public int OtherProperty { get { return 3; } }
}
static class Program
{
    static int someMethod() { return 3; }
    static void Main()
    {
        Foo foo = new Foo();
        Test<Foo>(x => x.Bar.ExtMethod(5), foo);
        Test<Foo>(x => x.Bar.ExtMethod(new object()), foo);
        Test<Foo>(x => x.Bar.ExtMethod(someMethod()), foo);
        Test<Foo>(x => x.Bar.ExtMethod(x.someMethod()), foo);
        Test<Foo>(x => x.Bar.ExtMethod(x.OtherProperty), foo);
    }
    static void Test<T>(Expression<Func<T, string>> expr, T instance)
    {
        if (expr.Body.NodeType != ExpressionType.Call)
        {
            throw new InvalidOperationException("Call expected");
        }
        var call = ((MethodCallExpression)expr.Body);
        if (call.Method != typeof(Program).GetMethod(
            "ExtMethod", BindingFlags.Static | BindingFlags.NonPublic))
        {
            throw new InvalidOperationException("ExtMethod expected");
        }
        // we know that ExtMethod has 2 args; pick myParameter (the 2nd);
        // then build an expression over arg, re-using our outer param
        var newLambda = Expression.Lambda<Func<T, object>>(
            call.Arguments[1], expr.Parameters[0]);

        // evaluate it and show the argument value
        object value = newLambda.Compile()(instance);
        Console.WriteLine(value);
    }
    static string ExtMethod(this object self, object myParameter) {
        return self.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)