簡體   English   中英

在調用自定義事件之前,為什么要檢查null?

[英]Why should I check for null before I invoke the custom event?

這兩個代碼示例之間用於調用事件有什么區別?

樣品1

public void OnDataChanged()
{
    if (DataChanged != null)
    {
        DataChanged(this);
    }
}

樣本2

DataChanged.Invoke(this);

我應該何時使用每種方法來調用自定義事件? 為什么有時我嘗試使用DataChanged.Invoke(this)調用事件時會得到NullReferenceException,但是當我將事件調用轉換為示例1中的方法時, DataChanged永遠不會變為null?

OnXYZ方法應始終遵循以下形式:

public void OnXYZ()
{
    var evt = XYZ;
    if (evt != null)
        evt(sender, e); // where to get e from differs
}

這種形式有幾個原因:

  1. if evt != null檢查確保我們不會嘗試調用null委托。 如果沒有人將事件處理程序連接到事件,就會發生這種情況。
  2. 在多線程場景中,由於委托是不可變的,一旦我們獲得委托的本地副本到evt ,我們可以在檢查非null之后安全地調用它,因為沒有人可以在if但在調用之前改變它。

e傳遞的內容有所不同,如果需要使用參數傳遞EventArgs后代,有兩種方法:

public void OnXYZ(string p)
{
    var evt = XYZ;
    if (evt != null)
        evt(sender, new SomeEventArgs(p));
}

或者更常見的是:

public void OnXYZ(SomeEventArgs e)
{
    var evt = XYZ;
    if (evt != null)
        evt(sender, e);
}

這個語法:

evt(sender, e);

只是一種不同的寫作方式:

evt.Invoke(sender, e);

另請注意,在您的類外部,事件是一個事件,您只能從中addremove事件處理程序。

在您的類的內部,事件是委托,您可以調用它,檢查目標或方法,遍歷訂閱者列表等。


此外,在C#6中引入了一個新的運算符, ?. - Null條件運算符 - 它基本上是if not-null, dereference縮寫,可以縮短這個方法:

public void OnXYZ(SomeEventArgs e)
{
    var evt = XYZ;
    if (evt != null)
        evt(sender, e);
}

進入這個:

public void OnXYZ(SomeEventArgs e)
{
    XYZ?.Invoke(sender, e);
}

可以通過使用表達身體成員進一步縮短:

public void OnXYZ(SomeEventArgs e) => XYZ?.Invoke(sender, e);

請注意,不能寫這個:

XYZ?.(sender, e);

所以你必須在這種情況下使用Invoke

當我將事件調用轉換為示例1中的方法時,DataChanged永遠不會變為空

然后你只是看兩種不同的場景。

如果你沒有聲明像public event EventHandler YourEvent = delegate { };那樣的public event EventHandler YourEvent = delegate { }; ,然后YourEventnull直到某些消費者訂閱它。

如果沒有訂閱DataChanged它將被設置為null,所以當你嘗試執行DataChanged.Invoke(this)時,你會得到一個NullRefException,因為它真的試圖做null.Invoke(this)。 附加if(DataChanged!= null)的原因是為了避免在沒有人訂閱該事件時發生這種情況。

我不相信當你使用Sample 1 DataChanged永遠不會為null時,它永遠不會到達.Invoke來拋出異常。 如果沒有人訂閱,它將始終為null。

您確定,在示例1中, DataChanged永遠不會為空嗎? 或者你只是沒有得到NullReference異常(因為你檢查if語句中的DataChanged 是否為空 )?

讓我們從基礎開始。 活動是一種特殊的代表。 當你調用DataChanged(this)和DataChanged.Invoke(this)時,它是一樣的。 為什么? 因為它編譯成同樣的東西。 總而言之, DataChanged(this)只是調用DataChanged.Invoke(this)的簡寫。

現在,為什么我們需要檢查空引用(如示例1中所示)。 基本上,當您調用事件時,您將調用訂閱此事件的所有方法(例如, DataChanged += someEventHandler )。 如果沒有人訂閱此事件,它將具有null值。 沒有分配方法來處理此事件。 換句話說:事件處理程序為null。

這就是為什么在調用事件之前檢查null是一個好習慣。

一個例子:

public void OnAbc(){
    var data=Abc;

    if(!String.IsNullOrEmpty(data))
        Abc(sender,e);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM