如何从lambda表达式获取引用实例的实例

时间:2010-08-31 08:53:56

标签: c# delegates lambda

我有这个lambda表达式Expression<Func<bool>> commandToExecute

然后我用一个方法传递一个类的实例:

_commandExecuter.ProcessCommand (() => aClass.Method())

如何在aClass方法中获取ProcessCommand的实例?

我想执行此类的一些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<bool>> commandToExecute
var referredProviderInstance = GetReferredProviderInstance(body);

这里的问题是,ConstantExpression的强制转换为Null。所以constantExpression始终为空。

有什么想法吗?

编辑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;
}

但是这里出现了一个新问题。我只获得了我的提供者的参考实例所在的窗体实例。

如何获取lambda表达式的真实对象aClass)?

2 个答案:

答案 0 :(得分:12)

这实际上是可行的,但这取决于您传递给此方法的内容。假设您有一个场景,您将所在类的实例方法传递给ProcessCommand

public class TestClass
{
    public void TestMethod()
    {
        ProcessCommand(() => MethodToCall());
    }
    public bool MethodToCall() { return true; }
    void ProcessCommand(Expression<Func<bool>> expression) { ... }
}

然后您可以使用以下ProcessCommand方法。这只能起作用,因为在此实例上调用了MethodToCall

void ProcessCommand(Expression<Func<bool>> 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<Func<bool>> expression) { ... }
}
public class CalledClass
{
    public bool MethodToCall() { return true; }
}

我们调用的方法现在位于另一个类中,并且不会在此实例上调用,而是在名为CalledClass的{​​{1}}实例上调用。但是编译器如何将calledClass变量传递给lambda表达式?没有任何内容可以定义字段calledClass,可以调用方法calledClass

编译器通过生成一个名为MethodToCall的字段的内部类来解决此问题。因此,calledClass方法现在变为:

ProcessCommand

稍微复杂一点,因为编译器必须生成匿名内部类。

答案 1 :(得分:2)

“开箱即用”是不可能的,你可以用反射破解某些东西,但是这是不可取的,它会非常倒退。
编辑:根据罗纳德的说法,实际上是可能的,但仍然相当倒退。这样的隐藏副作用使代码难以阅读和维护。

相反,您的ProcessCommand应该使用整个aClass对象,或者更优选地使用IMyCommand .Method()接口以及ProcessCommand所需的其他方法和属性。然后,aClass.GetType()类型应实现IMyCommand