English 中文(简体)
从MethodCallExpression访问调用对象
原标题:
  • 时间:2008-12-04 13:10:32
  •  标签:

我正在学习表达式树,我创建了一个方法,它接受一个

Expression<Func<bool>> 

如果它满足一些条件,就执行它 - 请参见下面的代码。

        private static void TryCommand(Expression<Func<bool>> expression)
        {
            var methodCallExpression = expression.Body as MethodCallExpression;
            if (methodCallExpression == null)
            {
                throw new ArgumentException("expression must be a MethodCallExpression.");
            }

            if (methodCallExpression.Object.Type != typeof (MyClass))
            {
                throw new ArgumentException("expression must be operating on an instanceof MyClass.");                
            }

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

            if(!success)
            {
                Console.WriteLine(methodCallExpression.Method.Name + "() failed with error code " + (func.Target as MyClass).GetError());
            }
        }

needs to be solved is how to improve the quality of the product. 需要解决的问题是如何提高产品的质量。

(func.Target as MyClass) 

是空的。很明显我做错了什么!我如何访问该方法正在操作的实例?

最佳回答

方法调用的目标是 MyClass 的一个实例,但委托本身并不是方法调用。它是在执行时执行方法调用的东西。

如果您查看func.Target,您将看到它是一个System.Runtime.CompilerServices.ExecutionScope。

现在您可以测试它并转换它,然后获取目标的“Locals”或“Globals”中的一个(不确定哪个)。但是,我怀疑更清晰的方法是改用Func<int>(或您的错误代码类型)并在首次执行委托时返回错误代码。然后,您甚至不需要表达式树。

根据您的评论,我建议:

public static void TryCommand(Expression<Func<MyClass,bool>> command,
                              MyClass c)
{
    // Code as before to find the method name etc.

    Func<MyClass, bool> compiled = command.Compile();

    if (!compiled(c))
    {
        Console.WriteLine(methodCallExpression.Method.Name
            + "() failed with error code " + c.GetError());
    }
}

你会用以下方式来调用它:

TryCommand(x => x.SomeMethod(), myClass);
问题回答

Akash, once you have a MethodCallExpression it s simple to recover the method caller. You must recover the MemberExpression and build an Expression tree that evaluates it.

请看下面的代码:


MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
MemberExpression memberExpression = (MemberExpression)methodCallExpression.Object;

Expression<Func<Object>> getCallerExpression = Expression<Func<Object>>.Lambda<Func<Object>>(memberExpression);
Func<Object> getCaller = getCallerExpression.Compile();
MyClass caller = (MyClass)getCaller();

希望这能有所帮助。

里卡多·拉塞达·卡斯特洛·布兰科

目标为空因为方法是静态的。在静态MethodInfo上的反射Invoke(..)将忽略目标。这很可能是一个扩展方法,在这种情况下,第一个参数是推断的目标。

由于LINQ的大部分基于扩展方法,因此在反射中,您将经常看到这种情况。





相关问题
热门标签