如何从lambda表达式获取引用实例的实例
我有这个lambda表达式Expression<Func> commandToExecute
然后我用一个方法传递一个类的实例:
_commandExecuter.ProcessCommand (() => aClass.Method())
如何在ProcessCommand
方法中获取aClass
的实例?
我想执行此类的一些addiontal方法或获取一些属性值。
这可能吗?
编辑:我现在已经编写了一个简单的静态助手方法来获取实例:
private static object GetReferredProviderInstance(Expression body) { var methodCallExpression = body as MethodCallExpression; if (methodCallExpression != null) { var constantExpression = methodCallExpression.Object as ConstantExpression; if (constantExpression != null) return constantExpression.Value; } return null; }
方法调用看起来像这样……
Expression body = commandToExecute.Body; // this is the method parameter Expression<Func> commandToExecute var referredProviderInstance = GetReferredProviderInstance(body);
这里的问题是,ConstantExpression的强制转换为Null
。 因此, constantExpression
始终为null。
有任何想法吗?
编辑2我修复了问题…
private static object GetReferredProviderInstance(Expression body) { var methodCallExpression = body as MethodCallExpression; if (methodCallExpression != null) { var memberExpression = methodCallExpression.Object as MemberExpression; if (memberExpression != null) { var constantExpression = memberExpression.Expression as ConstantExpression; if (constantExpression != null) return constantExpression.Value; } } return null; }
但是这里出现了一个新问题。 我只获得了我的提供者的参考实例所在的Windows窗体的实例。
我如何获得lambda表达式的真实对象 ( aClass
)?
这实际上是可能的,但这取决于您传递给此方法的内容。 假设您有一个场景,您将所在类的实例方法传递给ProcessCommand
:
public class TestClass { public void TestMethod() { ProcessCommand(() => MethodToCall()); } public bool MethodToCall() { return true; } void ProcessCommand(Expression> expression) { ... } }
然后,您可以使用以下ProcessCommand
方法。 这只能起作用,因为在此实例上调用了MethodToCall
。
void ProcessCommand(Expression> expression) { var lambda = (LambdaExpression) expression; var methodCall = (MethodCallExpression) lambda.Body; var constant = (ConstantExpression) methodCall.Object; var myObject = constant.Value; }
更复杂的情况如下:
public class CallingClass { public void TestMethod() { var calledClass = new CalledClass(); ProcessCommand(() => calledClass.MethodToCall()); } void ProcessCommand(Expression> expression) { ... } } public class CalledClass { public bool MethodToCall() { return true; } }
我们调用的方法现在在另一个类中,并且不在此实例上调用,而是在名为calledClass
实例上调用。 但是编译器如何将calledClass
变量传递给lambda表达式? 没有什么可以定义一个calledClass
的字段,可以调用calledClass
方法。
编译器通过生成一个名为calledClass
字段的内部类来解决这个calledClass
。 结果, ProcessCommand
方法现在成为:
public void ProcessCommand(Expression> expression) { // The expression is a lambda expression with a method call body. var lambda = (LambdaExpression) expression; var methodCall = (MethodCallExpression) lambda.Body; // The method is called on a member of some instance. var member = (MemberExpression) methodCall.Object; // The member expression contains an instance of the anonymous class that // defines the member... var constant = (ConstantExpression) member.Expression; var anonymousClassInstance = constant.Value; // ...and the member itself. var calledClassField = (FieldInfo) member.Member; // With an instance of the anonymous class and the field, we can get its value. var calledClass = (CalledClass) calledClassField.GetValue(anonymousClassInstance); }
稍微复杂一点,因为编译器必须生成一个匿名内部类。
它不可能“开箱即用”,你可以用reflection破解某些东西,但这是不可取的,它将是非常倒退的。
编辑:实际上根据罗纳德可能,但仍然相当倒退。 这样的隐藏副作用使代码难以阅读和维护。
相反,您的ProcessCommand应该使用整个aClass
对象,或者更优选的是IMyCommand
.Method()
的IMyCommand
接口以及ProcessCommand
所需的其他方法和属性。 然后aClass.GetType()
类型应该实现IMyCommand
。