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

发布于 2024-09-16 19:45:39 字数 1842 浏览 3 评论 0 原文

我有这个 lambda 表达式 Expression> commandToExecute

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

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

How do I get the instance of aClass inside the ProcessCommand method?

我想执行此类的一些附加方法或获取一些属性值。

这可能吗?

编辑: 我现在已经编写了一个简单的静态帮助器方法来获取实例:

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 始终为 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)?

I have this lambda expression Expression<Func<bool>> commandToExecute

Then I pass an instance of a class in there with a method:

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

How do I get the instance of aClass within the ProcessCommand method?

I want to execute some addiontal methods of this class or get some property values.

Is this possible?

EDIT:
I now have written a simple static helper method to get the instance:

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

The method call looks like this ...

Expression body = commandToExecute.Body; // this is the method parameter Expression<Func<bool>> commandToExecute
var referredProviderInstance = GetReferredProviderInstance(body);

The problem here is, that the cast to the ConstantExpression results into Null. So the constantExpression is always null.

Any ideas?

EDIT 2
I fixed the problem ...

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

But here comes a new problem. I only get the instance of the windows form where the reffered instance of my provider is located.

How do I get the real object (aClass) of the lambda expression?

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

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

发布评论

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

评论(2

(り薆情海 2024-09-23 19:45:39

这实际上是可能的,但这取决于您传递给该方法的内容。假设您有这样的场景,将所在类的实例方法传递给 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; }
}

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

编译器通过生成一个内部类来解决这个问题,该内部类具有一个名为 usedClass 的字段。结果,ProcessCommand 方法现在变成这样:

public void ProcessCommand(Expression<Func<bool>> 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);
}

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

This is actually possible but it depends on what you pass into this method. Suppose you have the scenario where you pass an instance method of the class that you are in to ProcessCommand:

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

Then you can use the following ProcessCommand method. This only works because MethodToCall is called on this instance.

void ProcessCommand(Expression<Func<bool>> expression)
{
    var lambda = (LambdaExpression) expression;
    var methodCall = (MethodCallExpression) lambda.Body;
    var constant = (ConstantExpression) methodCall.Object;
    var myObject = constant.Value;
}

The more complicated scenario is as follows:

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

The method we are calling is now in another class and isn't called on this instance but on an instance of CalledClass called calledClass. But how does the compiler pass the calledClass variable into the lambda expression? There is nothing that defines a field calledClass that the method MethodToCall can be called on.

The compiler solves this by generating an inner class with one field with the name calledClass. As a result the ProcessCommand method now becomes this:

public void ProcessCommand(Expression<Func<bool>> 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);
}

Slightly more complicated because the compiler has to generate an anonymous inner class.

他夏了夏天 2024-09-23 19:45:39

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

相反,您的 ProcessCommand 应该采用整个 aClass 对象,或更佳的是带有 .Method()IMyCommand 接口以及 .Method() 的附加方法和属性代码>ProcessCommand需要。那么aClass.GetType()类型应该实现IMyCommand

It is not possible "out of the box", you may be able to hack something with reflection, but that is not advisable, it will be very backwards.
Edit: Actually possible according to Ronald, but still quite backwards. Hidden side effects like this make the code hard to read and maintain.

Instead your ProcessCommand should take either the whole aClass object or more preferably an IMyCommand interface with .Method() and the additional methods and properties that ProcessCommand needs. Then the aClass.GetType() type should implement IMyCommand.

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