【问题标题】:How do I subscribe to an event of an object inside an expression tree?如何订阅表达式树中对象的事件?
【发布时间】:2009-12-24 04:36:37
【问题描述】:

抱歉,我想不出更好的标题。这是一个由两部分组成的问题,只有放在一起才有意义。

假设我有一个这样的构造函数

public Fact(INotifyPropertyChanged observable, Func<bool> predicate)
{
    this.predicate = predicate;
    observable.PropertyChanged += (sender, args) =>
                     PropertyChanged(this, new PropertyChangedEventArgs("Value"));

}

这就是它的使用方式

new Fact(Model.AllowEditing, () => Model.AllowEditing);

其中 AllowEditing 是一种 INotifyPropertyChanged

我想将构造函数重构为

public Fact(Expression<Func<bool>> expression)

所以可以这样调用

new Fact(() => Model.AllowEditing);

问题是如何解析该表达式以从表达式树中获取“可观察”然后订阅其事件?

上面的代码不是我的,它来自 Ayende 最近的一个例子,如果有人想看看 Fact 类是如何被使用的,这里是完整的源代码http://github.com/ayende/Effectus

【问题讨论】:

    标签: .net events expression-trees


    【解决方案1】:

    基本上,在这种情况下您需要的对象存储在 expression.Body.Expression 中。您将需要编译并执行表达式树来获取它。此外,您可能需要检查该类型是否真正实现了您的接口,以及谓词是否是您真正想要的。

    这是一个非常粗略的代码:

    public Fact(Expression<Func<bool>> predicate)
    {        
        this.predicate = predicate;
        MemberExpression body = predicate.Body as MemberExpression;
    
        // Check that you get a valid lambda expression, 
        // like object.Member, not something like !object.Member
        if (body == null) 
             throw new ArgumentException("'" + predicate + "': is not a valid expression for this method");
        var type = body.Expression.Type;
    
        // Check if type implements INotifyPropertyChanged using reflection  
        // ...
    
        INotifyPropertyChanged observable = 
        Expression.Lambda<Func<INotifyPropertyChanged>>(body.Expression).Compile()();
        //...
    }
    

    【讨论】:

    • 谓词不是以 MemberExpression 的形式出现,而是 UnaryExpression。所以我玩弄它,但仍然无法开始工作。我喜欢你的 EExpression.Lambda>(body.Expression).Compile()();这是一些严肃的代码。
    • 嗯……怎么可能是UnaryExpression?要获得一元表达式,您需要提供一个带有一元运算的 lambda 表达式。例如,!(Model.AllowEditing)、-Model.AllowEditing 或 Model.AllowEditing++。但这就是我所说的“检查谓词是否是你真正要找的东西”的意思。基本上,你只想在这里接受 MemberExpression,如果“body”为空,你应该抛出一个像“InvalidArgument”这样的异常。至于 Compile()(),请注意实际上它是一个繁重的操作。不要过度使用它。
    • 我不知道为什么,我在这方面的知识仍然有限。虽然这是在调试器中向我报告的。
    • 你能把调用这个构造函数的确切代码贴出来吗?我敢打赌它看起来像 new Fact(() => !Model.AllowEditing);
    • 是的,我这样称呼它 new Fact(() => Model.AllowEditing);然而值得指出的是,AllowEditing 不是 bool,它来自一个类包装类 Obserable,所以它是 Obserable。如果您有时间看一下,可以在这里找到课程代码github.com/ayende/Effectus 抱歉,这几周的课程我有点忙。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 2010-10-22
    • 2022-10-17
    • 2010-11-20
    • 1970-01-01
    相关资源
    最近更新 更多