2009-03-04 44 views
4

所以我堅持固定/維護另一個程序員代碼(BLECH)設置/刪除事件處理程序的.Net

我的規則堅定的教授,「如果沒壞不要修復它!」所以depsite每次遇到可怕的代碼時都想改變一些東西,我只限於改變絕對最小數量的代碼來完成所需的修復。但是在某些情況下,我需要了解一些內容,然後再試着去改變它。

我碰到這一點在這裏:

region.LineSelected = (x) => { }; 

,我想知道,如果它是與此相同:

region.LineSelected = null; 

我想是100%肯定的什麼樣的第一行是做在我改變它的方法之前。

回答

8

根據我目前對這個主題的看法編輯

他們不一樣。 lambda版本將一個事件處理程序添加到一個空的匿名方法中。這允許其他代碼自由引發LineSelected()而不用擔心它是否爲空(即沒有偵聽器)。

例如,

var lineSelected = this.LineSelected; 

if (lineSelected != null) 
{ 
    lineSelected(EventArgs.Empty); 
} 

如果事情引發該事件的如果但在此之前後在另一個線程從LineSelected退訂上面的語句可以拋出一個NullReferenceException。 將LineSelected分配給一個臨時變量,然後引發可以調用未訂閱的事件偵聽器。 將事件處理程序分配給局部變量是處理空委託的推薦方法。

通過添加一個空的委託,其他代碼總是能夠調用LineSelected而不用擔心NullReferenceException。 通過將多播事件委託分配給本地變量,可以確保該值不能被另一個線程修改。

+0

你能解釋一點嗎? – 2009-03-04 17:02:27

+0

好的,感謝編輯,我現在明白了。 – 2009-03-04 17:06:22

+0

很高興有幫助。 – 2009-03-04 17:06:50

1

不,它不是一回事 - 第一行將LineSelected指定爲與null完全不同的空代表。

發現差異的最簡單方法是查看編譯器在使用lambda語法時爲其生成的代碼。此代碼:

using System; 

class Program 
{ 
    static void Main() 
    { 
     Action<int> func0 = (x) => { }; 
     Action<int> func1 = null; 
    } 
} 

真編譯成這樣:

internal class Program 
{ 
    // Methods 
    private static void Main() 
    { 
     Action<int> func0 = delegate (int x) { 
     }; 
    } 
} 

注意,編譯器很聰明,因爲它被設置爲null,而不是其他地方引用刪除func1。但請注意func0仍然存在,並且設置爲代表,儘管與null完全不同但與此不同。

2

我想不出任何理由有第一行代碼。我唯一能想到的是在引發LineSelected事件時,如果在類中有第一行代碼,則不需要檢查LineSelected事件是否爲空。即:

if (this.LineSelected != null) 
{ 
    LineSelected(this,new EventArgs()); 
} 

相反,你可以引發沒有空檢查的事件。

但是,對於第二行代碼,您需要檢查是否有空值。

1

它們不一樣,因爲事件處理程序已設置。

可以說是公開LineSelected類,忘了:

if(LineSelected != null) 
    LineSelected(...) 

如果該類被調用LineSelected,沒有人聽,那麼它會拋出NullReferenceException異常

注意,你可以也可以這樣做(在區域內)以避免競爭條件:

var event = LineSelected; 如果(事件!= NULL) 事件(...

1

我認爲這是一個技術,避免每次事件null檢查。

如果LineSelected事件提高代碼沒有一個適當的空檢查,那麼這將導致異常:

region.LineSelected = null; 

/* no event handlers added to LineSelected */ 

class Region { 
    void OnLineSelected() { 
     // Null error! 
     LineSelected(); 
    } 
} 

但是,如果有一個空的無副作用的處理程序添加到它,那麼上面的代碼將工作得很好,即使沒有人處理程序添加到該事件,因爲總會有那個空的處理器連接。

1

要展開什麼理查德和安德魯說,它是

region.LineSelected = delegate {}; 

相當於這意味着當你提高的情況下,你並不需要先檢查空,因爲它有一個代表(在小的性能價格擊中)

2

這不是一個事件處理程序,這是一個簡單的代理。 (必須用+ =和 - =來修改事件處理程序以附加和分離事件)。

如前所述,將委託屬性設置爲空處理程序意味着在調用委託之前不必執行空檢查(假設沒有其他設置可以將其設置爲空)。

這可能會使調用代碼更方便,但它不應該被混淆爲性能改進(通過消除檢查null的需要)。通常,委託方法調用的開銷將顯着高於空檢查的開銷。可能會有一些場景(例如,如果委託人有99.99%的時間是「真正的」實現),避免使用空值檢查可以提高性能,但很難想象這種情況下,那裏的性能差異可能足以影響值得一提的是,這也不能保證完全取消委託調用,而是爲了提高效率。