2009-12-20 53 views
1

對不起,我想不出一個更好的標題。這是一個兩部分問題,只能在一起理解。如何訂閱表達式樹中對象的事件?

說我有這樣的

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的例子最近的例子,這裏是喜歡完整的源代碼,如果有人想看看怎樣的事實類正在使用http://github.com/ayende/Effectus

回答

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()(); 
    //... 
} 
+0

謂語不進來作爲MemberExpression,它的UnaryExpression。所以我玩弄它,但仍然無法工作。 我喜歡你的EExpression.Lambda >(body.Expression).Compile()(); 這是一些嚴重的代碼來包裹我的頭。 – firefly 2009-12-23 16:32:52

+0

嗯......怎麼可能是UnaryExpression?要獲得一元表達式,您需要提供一個具有一元運算的lambda表達式。例如,!(Model.AllowEditing),-Model.AllowEditing或Model.AllowEditing ++。但這就是我的意思,「檢查謂詞是否是你真正想要的」。基本上,你只想在這裏接受MemberExpression,如果「body」爲空,你應該拋出一個異常,如「InvalidArgument」。對於Compile()(),請注意,實際上它是一個繁重的操作。不要過度使用它。 – 2009-12-23 18:16:16

+0

我不知道爲什麼,我在這方面的知識還很有限。儘管這是在調試器中向我報告的內容。 – firefly 2009-12-25 16:40:06