事件與委託趣談

2021-08-29 21:30:50 字數 4947 閱讀 3021

事件與委託似乎很難以理解,這是因為它們的使用方式與常用的編碼有很大的差別,例如通常編寫的都是同步**,呼叫乙個型別的方法,會即刻出現方法執行的結果,這是符合邏輯的。但在某些情況中,同步**未必滿足需求,拿公共汽車來打個比方,如果交通管制中心希望每一輛公車到達乙個站點時都傳送給自己乙個訊號以便自己能夠隨時掌握交通狀況,使用同步**,公汽物件肯定需要呼叫管制中心物件,這樣就出現了我們一直不願意看到的情況:兩個型別緊密地耦合在一起。既然要其它型別對自己的行為作出反應,親自呼叫其型別的方法似乎不可避免,在同步**中,很難避免這種緊密的型別呼叫關係。

另乙個差別是在一般情況下,我們只將屬性作為引數傳遞給方法,而很少會考慮將乙個方法傳遞給另乙個方法。

因此,這個用例實際上是兩種型別——董事長類與雇員類——之間的互動,下面的**將給讀者展示如何使用委託與事件機制實現這種互動:

首先,我們需要在董事長類與雇員類之間定義乙個委託型別,用於傳遞兩者之間的事件,這個型別就是乙個監視裝置或專門負責打小報告的監查人員:

public delegate void delegateclasshandle();

定義乙個委託的過程類似方法的定義,但它沒有方法體。定義委託一定要新增關鍵字

delegate

。由於定義委託實際上相當乙個類,因此可以在定義類的任何地方定義委託。另外,根據委託的可見性,也可以新增一般的訪問修飾符,如

public

、private

和protected。

委託的返回值型別為

void

,這並非表示委託型別本身帶有返回值,該返回值型別是指委託的目標函式型別,即它委託的乙個事件處理函式返回值是

void

型別。

新建乙個雇員類

employee

,其**如下:

public class employee }

}雇員類

employee

**中定義了乙個

delegateclasshandle

型別的事件

playgame

,它的定義方式也很特殊,首先必須使用關鍵字

event

,表示playgame

是乙個事件,同時還必須宣告該事件的委託型別為

delegateclasshandle

,即將來由該型別的委託物件負責通知事件。

如果有雇員開始玩遊戲,它將執行

games

方法,而只要該方法一被呼叫,就會觸發乙個事件

playgame

,然後董事長就會收到這個事件的訊息——有人在玩遊戲了。

董事長類**如下,他有乙個方法

notify

用於接收訊息:

public class admin }

employee

的playgame

事件如何與

admin

的notify

方法關聯起來呢?只需通過事件繫結即可實現,具體過程如下列**:

employee

employee = new

employee();

admin

admin = new

admin();

employee.games();

employee.playgame += new

delegateclasshandle(admin.notify);

通過delegateclasshandle

將兩個類的互動進行了繫結,當

employee.games

方法呼叫後,觸發

playgame

事件,而該事件將被委託給

admin

的notify

方法處理,通知董事長有雇員在上班時間玩遊戲。

但董事長並不滿足這種簡單的通知,他還想知道究竟是誰在上班時間違反規定。顯然,現在委託物件必須傳遞必要的引數才行,這個要求也可以很容易地辦到。事件的引數可以設定為任何型別的資料,在

.net

框架中,還提供了事件引數基類

eventargs

專門用於傳遞事件資料。 從該

eventargs

類派生乙個自定義的事件引數類

customeeventargs

,這個型別將攜帶雇員姓名和年齡資訊:

public class customeevetnargs : eventargs

public string name

set }

public int age

set }

}修改委託型別

delegateclasshandle

的定義,讓其攜帶必要的引數:

public delegate void delegateclasshandle(object sender, customeevetnargs e);

雇員類的**修改後如下:

public class employee

set }

private int _age;

set }

} }

在games

方法中,首先新建乙個

customeeventargs

物件,然後設定了必要的屬性

name

和age。

董事長的通知方法也必須相應地進行修改:

public class admin }

將兩個型別物件進行關聯的**也需要進行相應的修改:

employee

employee = new

employee();

employee.name = "mike";

employee.age = 25;

admin

admin = new

admin();

employee.games();

修改後的**執行的結果是,當

mike

呼叫games

方法玩遊戲時,會自動觸發

playgame

事件,而該事件攜帶相關資訊通知

admin

,後者的

notify

方法將接收到資料並輸出「

mike is

25」,告訴董事長是

mike,25

歲,正在上班時間玩遊戲。

委託是可以多路廣播(

mulitcast

)的,即乙個事件可以委託給多個物件接收並處理。在上面的用例中,如果有另一位經理與董事長具有同樣的癖好,也可以讓委託物件將雇員的

playgame

事件通知他。

首先定義經理類:

public class manager }

經理manager

型別的notify

方法與admin

一致,他也接受到相應的資訊。

委託的多路廣播繫結的方法仍然是使用

+=運算子,其方法如下面的**所示:

employee

employee = new

employee();

employee.name = "mike";

employee.age = 25;

admin

admin = new

admin();

manager

manager = new

manager();

employee.playgame += new

delegateclasshandle(manager.notify);

employee.games();

執行該方法,讀者將看到

admin

和manager

的notify

方法都會被事件通知並呼叫執行。通過這樣的方法,董事長和經理都會知道

mike

在玩遊戲了。

如果董事長不希望經理也收到這個通知,該如何解除

playgame

對manager

的事件繫結呢?同樣非常簡單,在

employee.games

方法被呼叫前執行下列語句即可:

employee.playgame -= new

delegateclasshandle(manager.notify);

讀者能夠從委託與事件的**中得出什麼結論嗎?兩個需要存在呼叫關係的型別,在各自的實現中卻沒有編寫實際的呼叫**,它們只是通過乙個事件和乙個第三方的委託型別完成了訊息的傳遞過程。兩個型別之間不存在任何的緊密耦合,它們看似鬆散地通過乙個委託物件中通訊,實現了本書一直宣傳的「高聚合」和「低耦合」觀點。

最後需要提醒讀者注意的,

employee

類中的games

方法在觸發事件

playgame

之前需要判斷該事件是否為

null

。當employee

物件的games

方法觸發事件

playgame

後,必須有乙個目標函式來處理這個事件,而該語句正是判斷該目標函式是否存在。如果將這個判斷去掉,且對事件不進行任何繫結而直接呼叫

games

方法,程式將在事件

playgame

處彈出乙個

nullreferenceexception

的異常。

employee.playgame += new

delegateclasshandle(admin.notify);

employee.playgame += new

delegateclasshandle(admin.notify);

public void games()

public event delegateclasshandle playgame;

public int age

public string name

employee.playgame += new

delegateclasshandle(admin.notify);

委託與事件

1.建立乙個類,分別建立加 減 乘 除四個方法,通過委託和事件,實現 輸入兩個計算數,完成所有的四個方法的呼叫,計算出結果顯示。建立乙個警察 policeman 類,乙個小偷 thief 類,例項化兩個類的物件,當policeman類中警笛鳴響 alarm 方法執行時,觸發小偷逃跑 runaway ...

委託與事件

委託就是以方法做引數進行傳遞,它定義的是方法的框架,如果用這個委託,所宣告的方法就必須按照給定的引數及返滬型別進行處理。宣告委託的方式 delegate 返回值型別 委託型別名 引數 比如delegate void stringprocess string s 注意這裡的除了前面的delegate,...

委託與事件

委託與事件 一 委託 delegate 1 委託是一種可以把引用儲存為函式的型別。2 在定義了委託後,就可以宣告該委託型別的變數,接著把這個變數初始化為與委託有相同返回型別和引數類別的函式引用,之後,就可以使用委託變數呼叫這個函式,就像該變數是乙個函式一樣。如 double multiply dou...