C 委託機制應用例解

2021-04-15 07:31:32 字數 4252 閱讀 8219

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

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

我們拋棄各種c#參考書中桀驁難懂的事件與委託概念,設想乙個情景來理解事件與委託的使用:有一家it公司,董事長不希望自己的雇員在上班時間玩遊戲,但又不可能每時每刻都盯著每個雇員,因此,他希望使用一種新的方式實現監視雇員的效果:如果有雇員違反規定,某個裝置或專門的監查人員將自動發出乙個訊息通知他,董事長只需要在事情發生時進行處理。

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

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

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.playgame +=

new delegateclasshandle(admin.notify);

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;

public int age

set

}public event delegateclasshandle playgame;

public void games()}}

在games方法中,首先新建乙個customeeventargs物件,然後設定了必要的屬性name和age。

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

public class

admin }

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

employee employee =

new employee();

employee.name =

"mike";

employee.age = 25;

admin admin =

new admin();

employee.playgame +=

new delegateclasshandle(admin.notify);

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(admin.notify);

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的異常。

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

C 委託機制

c 的委託機制,實際上相當於函式的指標。如下例項 1 定義乙個類 class person string name public void person this.name name private virtual void eat food food 在該類中定義了乙個eat方法。對該物件進行例項...

C 委託機制

委託在c 中應用非常廣泛。最近初學c 記錄 delegate 一般語法 首先宣告delegate public delegate void boilhandler int param 相比普通方法 public float scrollvalue 形式上只是多了乙個標誌 delegate而已。其實可...

C 委託機制

c 委託相當於c c 中的函式指標。函式指標用指標獲取乙個函式的入口位址,實現對函式的操作。委託與c c 中的函式指標的不同之處是 委託是物件導向的,型別安全的和保險的,是引用型別,因此對委託的使用要 先定義,後宣告,接著例項化,然後為引數傳遞給方法,最後才能使用 定義委託使用關鍵字delegate...