2015-01-06 87 views
2

我開始閱讀有關MVVM和一個模式我看到很多是:C#INotifyPropertyChanged的處理

public event PropertyChangedEventHandler PropertyChanged; 
//..... 

PropertyChangedEventHandler handler = this.PropertyChanged; 
if (handler != null) 
{ 
    var e = new PropertyChangedEventArgs(propertyName); 
    handler(this, e); 
} 

爲什麼要費心去申報這handler變量?它只是在我看來是不必要地複雜的代碼,但我可以看到這甚至在微軟自己的教程,爲什麼不只是使用它作爲:

if (this.PropertyChanged != null) 
{ 
    var e = new PropertyChangedEventArgs(propertyName); 
    this.PropertyChanged(this, e); 
} 

回答

9

存儲關閉PropertyChanged事件是線程安全的。事實上,你應該在技術上與所有這樣做。

分配創建事件及其處理程序(不是一個參考,這將是無用的),這意味着您避免該事件處理程序設置爲null它通過null檢查之後的場景的副本。這可以避免可能會引發NullReferenceException的競爭條件。

實際上,UI並不經常將該屬性設置爲null。爲了安全起見,並且使用良好的做法,您應該關閉處理程序。

+0

哦有趣的知道!因此,如果該屬性爲null,則由處理程序創建的副本將正確調用某些處置的對象?這不是一個問題嗎? – mFeinstein

+0

對不起,你是什麼意思「所以樣品不包括它」?我幾乎可以在網上找到的幾乎所有示例代碼中看到這段代碼 – mFeinstein

+0

@mFeinstein對於第一個問題,有很多情況下事件處理程序可以設置爲null,但舊對象不會丟棄,所以不必*一個問題,儘管它*可能是一個。第二,我指的是微軟的教程。 – BradleyDotNET

6

我只是想爲BradleyDotNET的答案增加幾個觀點。

Jeffrey Richter在他的書CLR via C#中指出,該模式仍然不能保證是線程安全的,因爲編譯器可以優化掉本地變量(儘管當前版本的編譯器沒有進行優化)。他建議使用Volatile.Read在技術上是正確的:

PropertyChangedEventHandler handler = Volatile.Read(ref PropertyChanged); 
if (handler != null) 
{ 
    var e = new PropertyChangedEventArgs(propertyName); 
    handler(this, e); 
} 

在現實中,雖然,其他的模式得到廣泛應用,微軟將很可能永遠不會做出改變,將打破如此多的應用的編譯器。其他


的一點是,你實際上可以add an empty dummy delegate到您的活動,象下面這樣:

public event PropertyChangedEventHandler PropertyChanged = delegate { }; 

這意味着你不必擔心任何空檢查,因爲該事件已在至少一個附加的處理程序開始。不過,這種做法有爭議,因爲它似乎會導致性能損失(理論上你會爲每個事件調用添加額外的調用)。我個人避免使用它,因爲我寧願忍受比膨脹的運行時性能更臃腫的代碼。


This blog post by Eric Lippert關於這個話題是一個很好的閱讀。

+0

難道你還不能爲事件分配'null'嗎?快速測試顯示分配有效。 – BradleyDotNET

+0

@BradleyDotNET是的,我認爲你是對的。你只能在擁有事件的類中做這件事,所以如果你擁有這個類,那麼你至少可以控制它是否被設置爲null。但是,是的,仍然不是100%安全。 – McGarnagle