事件與委託似乎很難以理解,這是因為它們的使用方式與常用的編碼有很大的差別,例如通常編寫的都是同步**,呼叫乙個型別的方法,會即刻出現方法執行的結果,這是符合邏輯的。但在某些情況中,同步**未必滿足需求,拿公共汽車來打個比方,如果交通管制中心希望每一輛公車到達乙個站點時都傳送給自己乙個訊號以便自己能夠隨時掌握交通狀況,使用同步**,公汽物件肯定需要呼叫管制中心物件,這樣就出現了我們一直不願意看到的情況:兩個型別緊密地耦合在一起。既然要其它型別對自己的行為作出反應,親自呼叫其型別的方法似乎不可避免,在同步**中,很難避免這種緊密的型別呼叫關係。
另乙個差別是在一般情況下,我們只將屬性作為引數傳遞給方法,而很少會考慮將乙個方法傳遞給另乙個方法。
因此,這個用例實際上是兩種型別——董事長類與雇員類——之間的互動,下面的**將給讀者展示如何使用委託與事件機制實現這種互動:
首先,我們需要在董事長類與雇員類之間定義乙個委託型別,用於傳遞兩者之間的事件,這個型別就是乙個監視裝置或專門負責打小報告的監查人員:
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...