我正在尝试了解表达式树,并且我创建了一个采用
的方法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());
}
}
问题
(func.Target as MyClass)
为空。显然我做错了!如何访问该方法正在运行的实例?
答案 0 :(得分:3)
Akash,一旦你有一个MethodCallExpression,恢复方法调用者很简单。 您必须恢复MemberExpression并构建一个表达式树来评估它。
请参阅以下代码:
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();
希望这有帮助,
Ricardo Lacerda Castelo Branco
答案 1 :(得分:1)
方法调用的目标是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);
答案 2 :(得分:1)
目标为null,因为该方法是静态的。在反射中静态MethodInfo上的Invoke(..)将忽略目标。这可能是一种扩展方法,在这种情况下,第一个参数是推断目标。
由于大多数LINQ都基于扩展方法,因此您会看到这种情况经常发生反射。