日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

事件的记忆碎片

發布時間:2025/1/21 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 事件的记忆碎片 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

?

委托類型的實例是存儲著一個方法,并通過委托來調用那個方法,但是委托還有其他的用途。

先講一個模式:publish-subscribe(訂閱-發布)

它是應對這樣的一個場景情形:就是把單一事件的通知廣播給多個訂閱者。

?

這句話通俗一點講的話就是:

現在有方法ABCDE,自己想調用這五個方法中的全部或者部分方法。但是又不想一個一個顯式的去調用,因為如果方法很多的話就會形成一個代碼的堆砌,不夠簡潔,時間一長也不好維護。這時候有一個想法就是能有一個“方法F”來收集自己想要調用的方法就好了,最后自己只要調用“方法F”就可以調用所有自己想要調用的方法。

到這邊有人可能就感覺不是很自然,感覺有點陌生,沒有關系,我也是和你一樣很陌生,本文就是幫助你對publish-subscribe(訂閱-發布)這個模式的熟悉并且完全掌握

好的,publish-subscribe(訂閱-發布)先講到這邊。本文的第一句話就提到委托還有其他的用途。具體是指:一個委托變量可以引用一系列委托,在這一系列委托中,每一個委托都會順序指向一個后續的委托,從而形成一個委托鏈。只要調用這個委托的方法對象,在這個委托鏈上的所有方法就會按照委托鏈的順序一一執行。我們在這邊可以做一個猜想:委托變量可以調用多個方法,是不是“方法F”就是用委托變量來實現的呢? 其實答案就是這樣。

?

具體的場景描述:

來考慮一個溫度控制的例子。一個加熱器和一個冷卻器連接到同一個自動調溫器。為了控制加熱器和冷卻器的打開和關閉,要向他們通知溫度的變化。自動調溫器將溫度的變化發布給多個訂閱者----也就是加熱器和冷卻器。

?

一、定義訂閱者的方法

public class Cooler

??? {

??????? public Cooler(float temperature)

??????? {

??????????? Temperature = temperature;

??????? }

??????? public float Temperature { get; set; }

??????? public void OnTemperatureChanged(float newTemperature)

??????? {

??????????? if (newTemperature > Temperature)

??????????? {

??????????????? Console.WriteLine("Cooler:ON");

??????????? }

??????????? else

??????????? {

??????????????? Console.WriteLine("Cooler:Off");

??????????? }

??????? }

}

??? public class Heater

??? {

??????? public Heater(float temperature)

??????? {

??????????? Temperature = temperature;

??????? }

??????? public float Temperature { get; set; }

??????? public void OnTemperatureChanged(float newTemperature)

??????? {

??????????? if (newTemperature < Temperature)

??????????? {

?? ?????????????Console.WriteLine("Heater:ON");

??????????? }

??????????? else

??????????? {

??????????????? Console.WriteLine("Heater:Off");

??????????? }

??????? }

}

這兩個類幾乎完全一致,兩個類都提供了一個OnTemperatureChanged方法,調用OnTemperatureChanged就是為了向HeaterCooler指出溫度變化,并決定是否讓設備啟動。在這里,兩個OnTemperatureChanged方法都是訂閱者方法。作為訂閱者方法很重要的是它們的參數和返回值類型必須和自動調溫器中的委托匹配。

?

二、定義發布者

?

Thermostat類負責向heatercooler對象實例報告溫度的變化。

??? public class Thermostat

??? {

??????? public delegate void TemperarureChangeHandler(float newTemperature);

??????? public TemperarureChangeHandler OnTemperatureChange

??????? { get; set; }

??????? public float CurrentTemperature//接受當前的溫度

??????? { get; set; }

}

這個類的第一個成員是TemperarureChangeHandler 委托。定義了訂閱者的方法類型,就是說在HeaterCooler類中的OnTemperatureChanged成員方法和TemperarureChangeHandler委托是匹配的。OnTemperatureChange成員屬性是TemperarureChangeHandler委托類型的,將會用來存儲著訂閱者列表。最后一個CurrentTemperature屬性是用來接收當前的溫度的。

?

三、連接發布者和訂閱者

??? public class Program

??? {

??????? Thermostat thermostat = new Thermostat();

??????? Heater heater = new Heater(60);

??????? Cooler cooler = new Cooler(80);

??????? string temerature;

??????? thermostat.OnTemperatureChange += heater.OnTemperatureChanged;

??????? thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;

??????? Console.Write("Enter temperature:");

??????? temerature = Console.ReadLine();

??????? thermostat.CurrentTemperature = int.Parse(temerature);

}

注意上述代碼使用+=運算符來直接賦值,向OnTemperatureChange委托注冊了兩個訂閱者。但是目前還沒有寫任何代碼將溫度變化發布給訂閱者。

?

四、調用委托,向訂閱者通知溫度的變化

public class Thermostat

{

??? public float CurrentTemperature//當CurrentTemperature屬性每次變化的時候調用委托來向訂閱者通知溫度的變化

??? {

??????? get

??????? {

??????????? return _CurrentTemperature;

??????? }

??????? set

??????? {

??????????? if (value != CurrentTemperature)

??????????? {

??????????????? _CurrentTemperature=value;

??????????????? OnTemperatureChange(value);

??????????? }

??????? }

??? }

private float _CurrentTemperature;

}

成功了成功了,現在對CurrentTemperature賦值包含了一些特殊的邏輯,可以向訂閱者通知CurrentTemperature發生了變化。為了向所有的訂閱者發出通知,只需執行一個簡單的C# 語句即:OnTemperatureChange(value); 這個語句將溫度的變化發給CoolerHeater的對象,只需執行一個調用,即可向多個訂閱者發出通知。這里的實現就是基于一個委托變量可以保存一個委托鏈。

?

五、在調用委托之前必須檢查委托對象是否為空

public class Thermostat

{

??? public float CurrentTemperature//當CurrentTemperature屬性每次變化的時候調用委托檢查空值

??? {

??????? get

??????? {

??????????? return _CurrentTemperature;

??????? }

??????? set

??????? {

??????????? if (value != CurrentTemperature)

??????????? {

??????????????? _CurrentTemperature = value;

??????????????? TemperarureChangeHandler localOnChange = OnTemperatureChange;//OnTemperatureChange中發生的任何改變都會在localOnChange中反映出來

??????????????? if (localOnChange != null)

??????????????? {

??????????????????? localOnChange(value);

??????????????? }

?????? ?????}

??????? }

}

private float _CurrentTemperature;

}

在這里,并不是一開始就檢查空值,而是首先是將OnTemperatureChange賦值給 localOnChange因為OnTemperatureChange?的訂閱者被不是同一個線程的方法移除時候,那么不會觸發NullReferenceException異常。

?

六、處理來自訂閱者的異常

public class Thermostat

{

??????? public float CurrentTemperature//當CurrentTemperature屬性每次變化的時候調用委托并處理來自訂閱者的異常

?????? {

??????????? get

?????? ? {

??????????????? return _CurrentTemperature;

???????? }

??????????? set

???????? {

??????????????? if (value != CurrentTemperature)

??????????? {

??????????????????? _CurrentTemperature = value;

?

??????????????????? //OnTemperatureChange中發生的任何改變都會在localOnChange中反映出來

??????????????????? TemperarureChangeHandler localOnChange = OnTemperatureChange;

??????????????????? if (localOnChange != null)

????????? ?????? {

?

????????????????? //防止因為訂閱者的異常導致在異常后面的訂閱者不能接收到發布事件

??????????????????????? foreach (TemperarureChangeHandler handler in localOnChange.GetInvocationList())

????????????????? {

??????????????????????????? try

???????????????????? {

??????????????????????????????? handler(value);

???????????????????? }

??????????????????????????? catch (Exception exception)

???????????????????? {

??????????????????????????????? Console.WriteLine(exception.Message);

???????????????????? }

??????????????? ? }

?????????????? }

??????????? }

???????? }

???? }

??????? private float _CurrentTemperature;

}

?

委托鏈是將多個方法串聯在一起的,假如一個委托鏈上有ABC三個注冊的方法,但是假如A中出現異常,BC是不會繼續執行的,那么解決的辦法就是用foreach 上面的代碼就是解決方案。

?

七、事件的出現

講了這么多的還是沒有講到事件,哈哈,是不是被耍了啊。不要急,一會就會講到事件了啊。

我們看上面的委托處理還是很不錯的,不過有兩點不是很好

1、?Main方法中給委托注冊事件

???? thermostat.OnTemperatureChange += heater.OnTemperatureChanged;

???? thermostat.OnTemperatureChange += cooler.OnTemperatureChanged;

假設我們不小心的把+=寫成了=,就會出現我們不想要的結果,就會在thermostat.OnTemperatureChange 中保存最后一個賦值的方法,而之前的都會被重寫,容易出錯。

2、?委托可以在包容類之外被執行調用

?

還是在Main方法中可以加上這句話:

?

thermostat.OnTemperatureChange(56);

?

加上這句話會導致的結果是:即使thermostatCurrentTemperature沒有發生變化,OnTemperatureChange也能被調用。因此thermostat訂閱者有可能被通知說溫度變化了,而實際上CurrentTemperature的溫度并沒有變化。

?

C# event 關鍵字解決上面的兩個問題。代碼:

?

??? public class Thermostat

??? {

??????? public class TemperatureArgs : System.EventArgs

??????? {

??????????? public TemperatureArgs(float newTemperature)

??????????? {

??????????????? NewTemperature = newTemperature;

??????????? }

??????????? public float NewTemperature

??????????? { get; set; }

??????? }

??????? //public delegate void TemperarureChangeHandler(float newTemperature);

??????? public delegate void TemperarureChangeHandler(object sender,TemperatureArgs newTemperature);

??????? public event TemperarureChangeHandler OnTemperatureChange = delegate { };

?

??????? public float CurrentTemperature//當CurrentTemperature屬性每次變化的時候調用委托并處理來自訂閱者的異常

??????? {

??????????? get

??????????? {

??????????????? return _CurrentTemperature;

??????????? }

??????????? set

??????????? {

??????????????? if (value != CurrentTemperature)

??????????????? {

??????????????????? _CurrentTemperature = value;

??????????????????? TemperarureChangeHandler localOnChange = OnTemperatureChange;//OnTemperatureChange中發生的任何改變都會在localOnChange中反映出來

??????????????????? if (localOnChange != null)

??????????????????? {

??????????????????????? foreach (TemperarureChangeHandler handler in localOnChange.GetInvocationList())//防止因為訂閱者的異常導致在異常后面的訂閱者不能接收到發布事件

??????????????????????? {

??????????????????????????? try

??????????????????????????? {

??????????????????????????????? handler(this,new TemperatureArgs(value));

????????????????????????? ??}

??????????????????????????? catch (Exception exception)

??????????????????????????? {

??????????????????????????????? Console.WriteLine(exception.Message);

??????????????????????????? }

??????????????????????? }

??????????????????? }

??????????????? }

??????????? }

??????? }

??????? private float _CurrentTemperature;

}

有了這樣的聲明,在加上event關鍵字后,提供了我們需要的全部封裝。首先會禁止使用賦值運算符,然后只有包容類才能調用向所有的訂閱者發出通知的委托。


總結

以上是生活随笔為你收集整理的事件的记忆碎片的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。