Effective C#筆記 - 用null條件運(yùn)算符調(diào)用事件處理程序

使用事件的常用步驟:

  1. 定義事件參數(shù);
  2. 事件源類型中聲明事件;
  3. 注冊(cè)處理事件的方法,即監(jiān)聽(tīng);
  4. 再需要是,觸發(fā)事件。
public class CustomEventArgs: System.EventArgs
{
    public string EventData { get; private set; }

    public CustomEventArgs(string eventData)
    {
        EventData = eventData;
    }
}

public class CustomEventSource
{
    public System.EventHandler<CustomEventArgs> CustomEvent;

    public void DoWork()
    {
        // do other work

        // 最初的寫(xiě)法
        if(null != CustomEvent)
        {
            CustomEvent(this, new CustomEventArgs("event argument"));
        }

        // 有經(jīng)驗(yàn)的同事會(huì)告訴我們,需要這樣寫(xiě)
        //var handler = CustomEvent;
        //if(null != handler)
        //{
        //    handler(this, new CustomEventArgs("event argument"));
        //}
    }
}

public class EventUsage
{
    private CustomEventSource handlerDemo;

    public void Init()
    {
        handlerDemo = new CustomEventSource();
        handlerDemo.CustomEvent += HandleCustomEvent;
    }

    private void HandleCustomEvent(object sender, CustomEventArgs e)
    {
        Console.WriteLine($"event: {e.EventData}");
    }

    public void UnInit()
    {
        if(null != handlerDemo)
        {
            handlerDemo.CustomEvent -= HandleCustomEvent;
        }
    }
}

其實(shí)那會(huì)不是很理解為什么這么寫(xiě),然后他們就告訴我,這樣可以避免多線程使用時(shí)帶來(lái)的bug,而且不好查。就是當(dāng)前程序執(zhí)行完if語(yǔ)句之后,會(huì)被另一個(gè)線程打斷,并且另一個(gè)線程解除事件監(jiān)聽(tīng),也就是解除了事件訂閱,這樣事件處理程序成了null,這樣就引發(fā)了空引用的異常。所以會(huì)先賦值一個(gè),用賦值后的內(nèi)容去處理事件。原理是:該賦值會(huì)對(duì)賦值符號(hào)右邊的內(nèi)容做淺拷貝(創(chuàng)建新引用,并令其指向原來(lái)的事件處理程序),當(dāng)另一個(gè)線程注銷事件處理程序的時(shí)候,只會(huì)修改類實(shí)例中的handlerDemo字段,而不會(huì)把該處理程序同時(shí)從局部變量handler里面移走,這樣,handler中還保存著早前執(zhí)行淺拷貝時(shí)所記錄的事件訂閱者,這樣就不會(huì)出錯(cuò)了。

這樣的處理是線程安全的,但是會(huì)復(fù)雜一些,C#引入的null條件運(yùn)算符,可以解決這個(gè)問(wèn)題,即:

CustomEvent?.Invoke(this, new CustomEventArgs("event argument"));

現(xiàn)在編譯器也會(huì)智能提示我們這樣修改,這樣很方便,而且在語(yǔ)義上,與早期的if結(jié)構(gòu)類似,但區(qū)別在于?.運(yùn)算符左側(cè)內(nèi)容只會(huì)計(jì)算一次?,F(xiàn)在我已經(jīng)慢慢習(xí)慣這種使用方式了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容