事件的記憶碎片

2021-09-06 04:41:54 字數 4710 閱讀 2705

前言

委託型別的例項是儲存著乙個方法,並通過委託來呼叫那個方法,但是委託還有其他的用途。

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

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

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

現在有方法a、b、c、d、e,自己想呼叫這五個方法中的全部或者部分方法。但是又不想乙個乙個顯式的去呼叫,因為如果方法很多的話就會形成乙個**的堆砌,不夠簡潔,時間一長也不好維護。這時候有乙個想法就是能有乙個「方法f」來收集自己想要呼叫的方法就好了,最後自己只要呼叫「方法f」就可以呼叫所有自己想要呼叫的方法。

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

好的,publish-subscribe(訂閱-發布)先講到這邊。本文的第一句話就提到委託還有其他的用途。具體是指:乙個委託變數可以引用一系列委託,在這一系列委託中,每乙個委託都會順序指向乙個後續的委託,從而形成乙個委託鏈。只要呼叫這個委託的方法物件,在這個委託鏈上的所有方法就會按照委託鏈的順序一一執行。我們在這邊可以做乙個猜想:委託變數可以呼叫多個方法,是不是「方法f」就是用委託變數來實現的呢?

其實答案就是這樣。

具體的場景描述:

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

一、定義訂閱者的方法

public

class

cooler

public

float

temperature

public

void

ontemperaturechanged(float

newtemperature)

else

} }

public

class

heater

public

float

temperature

public

void

ontemperaturechanged(float

newtemperature)

else

} }

這兩個類幾乎完全一致,兩個類都提供了乙個ontemperaturechanged方法,呼叫ontemperaturechanged就是為了向heater和cooler指出溫度變化,並決定是否讓裝置啟動。在這裡,兩個ontemperaturechanged方法都是訂閱者方法。作為訂閱者方法很重要的是它們的引數和返回值型別必須和自動調溫器中的委託匹配。

二、定義發布者

thermostat

類負責向heater和cooler物件例項報告溫度的變化。

public

class

thermostat

public

float

currenttemperature//

接受當前的溫度

}

這個類的第乙個成員是

temperarurechangehandler

委託。定義了訂閱者的方法型別,就是說在heater和cooler類中的

ontemperaturechanged

成員方法和

temperarurechangehandler

委託是匹配的。

ontemperaturechange

成員屬性是

temperarurechangehandler

委託型別的,將會用來儲存著訂閱者列表。最後乙個

currenttemperature

屬性是用來接收當前的溫度的。

三、連線發布者和訂閱者

public

class

program

注意上述**使用+=運算子來直接賦值,向

ontemperaturechange

委託註冊了兩個訂閱者。但是目前還沒有寫任何**將溫度變化發布給訂閱者。

四、呼叫委託,向訂閱者通知溫度的變化

public

class

thermostat

set}

} private

float

_currenttemperature;

}

成功了成功了,現在對

currenttemperature

賦值包含了一些特殊的邏輯,可以向訂閱者通知

currenttemperature

發生了變化。為了向所有的訂閱者發出通知,只需執行乙個簡單的c# 語句即:

ontemperaturechange(value);

這個語句將溫度的變化發給cooler和heater的物件,只需執行乙個呼叫,即可向多個訂閱者發出通知。這裡的實現就是基於乙個委託變數可以儲存乙個委託鏈。

五、在呼叫委託之前必須檢查委託物件是否為空

public

class

thermostat

set}

} }

private

float

_currenttemperature;

}

在這裡,並不是一開始就檢查空值,而是首先是將

ontemperaturechange

賦值給localonchange

因為ontemperaturechange 

的訂閱者被不是同乙個執行緒的方法移除時候,那麼不會觸發nullreferenceexception異常。

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

public

class

thermostat

setcatch

(exception exception)}}

}}

} private

float

_currenttemperature;

}

委託鏈是將多個方法串聯在一起的,假如乙個委託鏈上有a、b、c三個註冊的方法,但是假如a中出現異常,b和c是不會繼續執行的,那麼解決的辦法就是用

foreach

上面的**就是解決方案。

七、事件的出現

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

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

1、 在main方法中給委託註冊事件

thermostat.ontemperaturechange += heater.ontemperaturechanged;

thermostat.ontemperaturechange += cooler.ontemperaturechanged;

假設我們不小心的把+=寫成了=,就會出現我們不想要的結果,就會在

thermostat.ontemperaturechange

中儲存最後乙個賦值的方法,而之前的都會被重寫,容易出錯。

2、 委託可以在包容類之外被執行呼叫

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

thermostat.ontemperaturechange(56);

加上這句話會導致的結果是:即使thermostat的currenttemperature沒有發生變化,ontemperaturechange也能被呼叫。因此thermostat訂閱者有可能被通知說溫度變化了,而實際上currenttemperature的溫度並沒有變化。

c# 用event 關鍵字解決上面的兩個問題。**:

public

class

thermostat

public

float

newtemperature

} //public delegate void temperarurechangehandler(float newtemperature);

public

delegate

void

temperarurechangehandler

(object

sender,temperatureargs

newtemperature);

public

event

temperarurechangehandler

ontemperaturechange = delegate

;

public

float

currenttemperature//

當currenttemperature屬性每次變化的時候呼叫委託並處理來自訂閱者的異常

setcatch

(exception

exception)}}

}}

} private

float

_currenttemperature;

}

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

記憶的碎片

彼得的龍 是一部優秀地動畫現實電影,對童話地重新解構並且重組,在現實中出現奇幻故事!情理之中,又在意料之內地完美結局,不愧是一部優秀地電影!根據1977年迪士尼經典動畫 妙妙龍 改編,是許多美國人的童年回憶。對於彼得與龍的相遇,就是溫情的故事,彼得稚嫩的手撫摸著龍,龍保護了他!之後的故事走向也是很符...

委託的記憶碎片

1 委託 定義 定義委託就是定義一類方法的型別,方法型別分類原則是根據引數和返回值的不同來分類的。什麼!你說方法分類還考慮返回值的型別嗎?方法的過載可不會考慮方法的返回值的不同,只看方法的引數列表的啊。是的,方法過載中的方法區分的方法是不看返回值的,但是定義委託是看方法返回值的。例如 兩個int引數...

記憶碎片 2015 09 11

今天啥都沒乾,整理一下 聽聽歌 坐等 好久沒有這麼休息過了。繼續聽歌 愛的海洋 演唱 曲婉婷 身在他鄉 志在遠方 你的愛讓我堅強 歌聲蕩漾 你為我鼓掌 沉浸在愛的海洋 從 不敢想到 想去做到 做到我想的 事實證明我並不像他們想象的那樣脆弱 我只是需要一盞燈 一架鋼琴 一支麥克風 身在他鄉 志在遠方 ...