2013-07-02 24 views
7

大多數時候,當我們使用MVVM我們使用INotifyPropertyChanged接口提供通知,以綁定,而一般實施看起來是這樣的:爲什麼我們應該使用臨時對象來提高事件?

public class MyClass : INotifyPropertyChanged 
{ 
    // properties implementation with RaisePropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

每當我從閱讀代碼也能正常工作對我來說專家 - 他們寫類似的代碼:

public class MyClass : INotifyPropertyChanged 
{ 
    // properties implementation with RaisePropertyChanged 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void RaisePropertyChanged(string propertyName) 
    { 
     var tempchanged = PropertyChanged; 
     if (tempchanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

我想知道背後是什麼創造了PropertyChanged事件的臨時對象的確切原因。

這只是一種好的做法,還是還有其他任何好處?

我發現喬恩的答案的答案,並在解釋例如:

Understanding C#: Raising events using a temporary variable

下面是示例代碼來了解這一點:

using System; 
using System.Collections.Generic; 
using System.Threading; 

class Plane 
{ 
    public event EventHandler Land; 

    protected void OnLand() 
    { 
      if (null != Land) 
      { 
       Land(this, null); 
      } 
     } 

    public void LandThePlane() 
    { 
      OnLand(); 
     } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
      Plane p = new Plane(); 
      ParameterizedThreadStart start = new ParameterizedThreadStart(Run); 
      Thread thread = new Thread(start); 
      thread.Start(p); 

      while (true) 
      { 
       p.LandThePlane(); 
      } 
     } 

    static void Run(object o) 
    { 
      Plane p = o as Plane; 
      while (p != null) 
      { 
       p.Land += p_Land; 
       p.Land -= p_Land; 
      } 
     } 

    static void p_Land(object sender, EventArgs e) 
    { 
      return; 
     } 
} 
+0

看到這篇文章, http://stackoverflow.com/questions/282653/checking-for-null-before-event-dispatching-thread-safe –

+0

見埃裏克利珀關於這個專題的文章,[事件和Races](http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx) – Brian

回答

25

你不是創建一個臨時對象。您正在使用局部變量來避免競爭條件。

在此代碼:

if (PropertyChanged != null) 
{ 
    PropertyChanged(...); 
} 

有可能爲PropertyChanged成爲null(由於最後用戶退訂)的無效支票後,這將意味着你得到一個NullReferenceException

當您使用本地變量時,確保您檢查無效的引用與用於引發事件的引用相同 - 因此您不會得到異常。仍然存在競爭條件,因爲您最終可能會呼叫剛退訂的用戶,但這是不可避免的。

+1

感謝Jon。這是瞭解情況的最簡單的方法。 – JSJ

4

這是爲了避免在檢查null(查看是否附加任何事件處理程序)和調用事件之間最後(或唯一)事件處理程序從事件中刪除的罕見情況。如果發生這種情況,你會得到一個NullReferenceException

如果您擔心內存泄漏 - 不要 - 它只是一個引用,而不是事件處理程序的副本。

更多細節可以發現here

0

它不僅使多線程場景打交道時的差異:當最後一個事件處理程序的!= null檢查後註銷,實際的通話可能會遇到在代碼1一個NullReferenceException

但是Code 2沒有這個問題,因爲Delegates(事件背後的概念)是不可變的,因此臨時變量的值不能改變。

不過,我會建議始終是一種最佳實踐與變種2去 - 這可能會節省你在未來;-)

1

這是線程安全的原因,好的做法頭疼。

在你的原代碼,這在理論上是可能的一個單獨的線程來之前以下行引發事件的if語句,但後刪除PropertyChanged處理。這會導致NullReferenceException

第二個示例消除了這種風險。

相關問題