Expression.Lambda() 的参数问题

发布于 2024-07-21 22:40:24 字数 1438 浏览 3 评论 0原文

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

我在运行时有以下扩展方法,

public static string ExtMethod(this object self, object myparameter);

可以通过多种方式调用它,我认为这些都是可能性:

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);

我需要做的是 给定“expr”和“T”,评估“myparameter

由于 x 的两种情况, 在 myparameter 中使用,我认为我需要创建以下形式的委托:

Expression<Func<T, object>> expr = x => [myparameter expression here]

我认为这可行:

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

var myparam = Expression.Lambda(myparameterExpr, expr.Parameters).Compile().Invoke(someT)

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

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

var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT)

它工作正常。

我该如何解决这个问题?

谢谢

Update: This does work, I was being stupid :(

i have the following extension method

public static string ExtMethod(this object self, object myparameter);

at runtime this is called in any number of ways ways, i think these are all possibilities:

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);

what i need to do is evaluate the "myparameter", given "expr" and a "T"

because of the two cases where x is used in myparameter, i thought i needed to create a delegate of the form:

Expression<Func<T, object>> expr = x => [myparameter expression here]

i thought this would work:

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

var myparam = Expression.Lambda(myparameterExpr, expr.Parameters).Compile().Invoke(someT)

but for the expressions that do not involve x, i get TargetParameterCountException :(

in these cases, if i do:

var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT)

it works fine.

How do I solve this?

thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抽个烟儿 2024-07-28 22:40:24

好的; 追根究底; 行中:

var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT);

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

var myparam = Expression.Lambda(myparameterExpr,
             outerLambda.Parameters[0]).Compile().Invoke(someT);

这是一些计算内部参数的工作代码(给定参数类型的实例); 请注意,即使它涉及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();
    }
}

OK; got to the bottom of it; in the line:

var myparam = Expression.Lambda(myparameterExpr).Compile().Invoke(someT);

If you weren't trying to pass in a someT, this would work for those expressions that don't involve x in the argument; for those that do, you need to tell the lambda to include the parameter (the same one from the original lambda) - simply by:

var myparam = Expression.Lambda(myparameterExpr,
             outerLambda.Parameters[0]).Compile().Invoke(someT);

Here's some working code that evaluates the inner parameter (given an instance of the argument type); note that I use the parameter even if it doesn't involve an x - otherwise, what would it do with the instance?

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();
    }
}
卖梦商人 2024-07-28 22:40:24

如果您检查 expr.Parameters.Count 并且如果它为 0,则不带参数调用会怎样?

What if you check expr.Parameters.Count and if it's 0, invoke without the parameters?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文