1. 程式人生 > >C# ~ 從 委託事件 到 觀察者模式

C# ~ 從 委託事件 到 觀察者模式

委託

 委託本質是一個密封類,定義方法的型別,將方法作為方法的引數。委託包含一個具有相同簽名和返回值型別的有序的方法列表(呼叫列表)。
 委託宣告:public delegate void MyDel(string str); 編譯結果為:

public sealed class MyDel : System.MulticastDelegate
{
   public MyDel(object @object, IntPtr method);
   public virtual void Invoke(string str);
   public virtual void EndInvoke
(IAsyncResult res); public virtual IAsyncResult BeginInvoke(string str, AsyncCallback callback, object @object); }

擴充套件:自定義委託類 MyDel 繼承於類 MulticastDelegate,MulticastDelegate 類是 System.Delegate 的子類,支援多路廣播委託並維護對應的委託列表。兩個常用 public 屬性:
 · Target:委託呼叫的方法所屬的類例項的引用,若方法是靜態方法,則為 null;
 · Method:委託所表示的方法的資訊;
  建構函式中的引數:object 為物件例項的引用,methodPtr 用於標識回撥方法,分別對應 Target 和 Method。一個常用 public 方法:
 ·

 public Delegate[] GetInvocationList();委託的呼叫列表中方法的陣列;
參考C# - 委託鏈委託的本質論
 
1. 建立委託(物件)

 [修飾符] delegate 返回值型別 MyDel(引數列表);
 MyDel objDel1 = new MyDel(obj.例項方法);   或 MyDel objDel1 = obj.例項方法;
 MyDel objDel2 = new MyDel(Class.靜態方法); 或 MyDel objDel2 = Class.靜態方法;

  · 為委託物件分配記憶體;
  · 把方法新增到委託物件的呼叫列表中;

2. 組合委託 (Combining Delegate)
 委託是恆定的,委託物件被建立後就不會再被改變。委託組合拷貝的是運算元的副本,只有相同型別的委託才可以組合。委託的組合和移除分別用"+"和"-";

 MyDel objDel = objDel1 + objDel2;

3. 呼叫委託

 objDel(引數列表);    或   objDel.Invoke(引數列表);

  用於呼叫委託的引數會去呼叫呼叫列表中的每個方法。
  · 呼叫帶返回值的委託:委託呼叫的返回值是其呼叫列表中最後一個方法的返回值。
  · 呼叫帶引用引數的委託:呼叫委託的引數會隨著呼叫列表中方法的呼叫而改變。
 :Invoke 是同步方法,BeginInvoke/EndInvoke 是非同步方法,但其呼叫者 myDel 的呼叫列表有且只能用一個方法,而 Invoke 沒有這個限制。Invoke and BeginInvoke 介紹

IAsyncResult res = myDel.BeginInvoke(委託的引數列表, null, null);            
myDel.EndInvoke(res);

4. 匿名委託
  匿名委託可以訪問其所在方法的區域性變數,具體 .Net委託和事件 - 匿名委託部分
 
5. Action<> 和 Func<> 以及 Predicate<>
  將委託的宣告和賦值合併,進一步簡化。Action<>沒有返回值,Func<>有返回值。

  // 委託的幾種賦值方法均可用在此處
  Func<int,bool> myDel = (Lambda表示式);
  Func<int,bool> myDel = new Func<int,bool>(函式名);

  Predicate<T> 是返回 bool 的泛型委託,可以理解為 Func<T,bool>的泛型委託的別名,多用於查詢的條件表示式。
 
 參考
 [1]. 從委託到匿名委託到Lambda表示式再到 Action<>和Func<>
 [2]. 深入分析委託與事件

事件

 參考深入理解事件的本質
 物件一是事件產生者或傳送者,物件二是事件接收者或訂閱者,物件一產生訊息,物件二響應並處理訊息(事件/訊息機制)。
 event 是 delegate 的高階形式,事件封裝了委託,委託封裝了方法。事件包含一個私有委託,事件提供對私有控制委託的結構化訪問,當事件觸發時,呼叫委託來依次呼叫呼叫列表中的方法。在事件中,委託是事件的發起者 sender 將 EventArgs 傳遞給處理者的管道。

1. 事件宣告
 儲存和呼叫事件處理程式。

 public [static] event 委託型別 Notify;

 推薦使用:事件使用標準的預定義委託型別

 public delegate void EventHandler(object sender, EventArgs e);

2. 事件註冊方法
 ·  方法形式
  [1]. 例項方法:publisher.Notify += subscriber.例項方法;
  [2]. 靜態方法:publisher.Notify += Subscriber.靜態方法;
 ·  委託形式
  [1]. 例項方法:publisher.Notify += new EventHandler(subscriber.例項方法);
  [2]. 靜態方法:publisher.Notify += new EventHandler(Subscriber.靜態方法);
 ·  匿名方法
  publisher.Notify += delegate(object source, EventArgs args) { … };
 ·  Lambda表示式
  publisher.Notify += (source, args) => { … };
 :publisher 是釋出者類物件;subscriber 是訂閱者類物件,Subscriber 是訂閱者類。

3. 事件訪問器(Event Accessor)
 事件訪問器表現為 void 方法,add 和 remove 訪問器均包含隱式值引數 value。通過為事件宣告自定義的事件訪問器,此時事件並未內嵌委託物件,需要自定義新增和移除註冊事件的方法來自行封裝一個委託的例項。事件的 add 和 remove 不能缺且必須有實現主體但可以為空。

 private MyEventHandler notify = null;   /// [1] 宣告委託的例項
 public event MyEventHandler Notify      /// [2] 事件封裝委託的例項
 {
   add      /// 增加
   {
     if (null != value)
       notify += value;
   }
   remove   /// 刪除
   {
     Delegate[] funList = notify.GetInvocationList();   /// 獲取呼叫列表
     if (-1 != Array.IndexOf(funList, value))
       notify -= value;             
   }
 }
函式指標 vs 委託

 回撥函式,Callback,在函式體內呼叫主呼叫函式中的函式。
 · 函式指標:儲存函式的入口地址,作為函式的引數、用於呼叫函式;
   委託:儲存函式的入口地址同時儲存呼叫該函式的類/類例項的引用;
 · 委託擴充套件性更好,支援多播委託(MulitCast)和非同步呼叫;

委託 vs 事件

 ·  委託支援"+"和"-"、"+="和"-="、賦值運算子"=";事件僅僅支援"+="和"-=";
 ·  Delegate 是類(型),Event 是成員,Event 成員型別派生於 Delegate;
 ·  委託常用來表達回撥,事件表達外發的介面;
 ·  委託:可以在類外部觸發、允許直接通過委託呼叫相應的處理函式:委託物件(引數列表);
    事件:只能在類內部觸發、通過釋出者類提供的 public 方法去呼叫。
 事件包含一個私有的委託物件。 事件的封裝性和易用性更好。

 public MyEventHandler Notify1;
 public event MyEventHandler Notify2;

 其實,Notify1 相當於 Class 裡面的 欄位Field,訪問級別 public ,Notify2 相當於 屬性Property,訪問級別也是 public,但是,Notify2 內部封裝了一個 訪問級別為 private 的 委託物件!(帶 event 關鍵字,編譯之後,委託物件變成 private,並自動生成一個與委託物件對應的事件)
 屬性封裝欄位,事件封裝委託。
  
 
 參考
 [1]. Event 詳解
 [2]. 談 C# 中的 delegate - hyddd - 部落格園
 [3]. 不懼面試 - 關於委託一個委託的例子

觀察者模式

 Observer Pattern,即 Subject-Observer,又稱監聽模式 (Source/Listener) 或 釋出-訂閱模式(Publisher-Subscriber)。Observer 模式定義物件間的一對多的依賴關係,當一個物件狀態改變時,依賴於它的其他物件會被自動告知並更新。Observer 模式是一種鬆耦合的設計模式。邏輯關係圖:

 :事件處理程式即被委託的方法。Observer 模式典例:報紙訂閱、簡訊分發、熱水器,可參考 委託和事件詳解 - 補充

問題進階
· 如何限制事件只允許一個客戶訂閱?
 將事件宣告為 private,然後提供兩個 public 方法用於註冊和取消。或利用事件訪問器。
· 如何獲得多個訂閱者的返回值?
 利用 Delegate 類的靜態方法 Delegate[] GetInvocationList(),委託/事件變數呼叫之,然後遍歷包含委託方法的陣列即可。

相關推薦

C# ~ 委託事件觀察模式

委託  委託本質是一個密封類,定義方法的型別,將方法作為方法的引數。委託包含一個具有相同簽名和返回值型別的有序的方法列表(呼叫列表)。  委託宣告:public delegate void MyDel(string str); 編譯結果為:

快速學習——10、委託事件-觀察模式(一)

這篇我們先不講委託事件,從一些理論來 物件直接的關係 一對一 :人只有一個身份證號碼 一對多:一個人可以有多個號碼 (qq號 電話號 車牌號 等) 多對多:多個人 多個號碼   觀察者模式 觀察者模式,又稱為釋出訂閱模式,基於一對多的原理。 定義了物件之間的一對

多播委託觀察模式聯合使用,以及委託事件的區別

首先我們先看一下多播委託: 使用委託時,首先我們宣告委託,委託語法一共有四種類型,分別時有參,無參,以及有無引數返回值。 1 public class DelegateShow //: System.MulticastDelegate,多播委託 2 { 3 public del

《Head First 設計模式》例子的C++實現(2 觀察模式

最近在學習設計模式,用的是 《Head First 設計模式》這本書。感覺這本書寫的還是很不錯的,深入淺出的介紹了各種常用的設計模式。唯一有點不方便的地方是這本書的例子全都是用的 Java 來實現的。而我主要是用 C++。所以就動手將書上的程式碼用 C++ 來實

C++屌屌的觀察模式-同步回撥和非同步回撥

目錄 一、概述 1、同步觀察者 2、非同步觀察者 二、效果展示 三、同步觀察者 四、非同步觀察者 五、相關文章

Unity之C#——委託事件觀察模式,貓和老鼠事例

委託與事件,觀察者模式,貓和老鼠事例     在Unity遊戲開發中,我們經常需要在一個類中,呼叫另一個類中的方法,比如,當玩家進入到某個地方,敵人就開始攻擊玩家。這時就需要利用委託與事件,設計觀察者模式。 此處我們利用貓和老鼠來簡單描述: 程式碼如下: Ca

設計模式(九)-觀察模式C#委託事件

書中引出的例子為,當Boss回來,前臺通知員工好好工作的場景。1、觀察模式將通知廣播給每一個客戶端,客戶端想知道目標的變化a、從目標拉取 b、通知的時候將變化傳遞給客戶端。拉取的方法,客戶端自由度較高,客戶端可以根據需求拉取。觀察者通知內容豐富,客戶端需要不要更新拉取變化。耦

C#設計模式-觀察模式事件的一點小小心得

由於經驗和能力有限,設計模式這種高大上的東西要研究下來,不知道要禿了多少根頭髮,作為一個初學者,也只能簡單的理解一下大概思路 最近剛好在惡補基礎,看到了事件event  看大佬的部落格和資料一大串,幾百行 還沒看已經暈掉了 只能先簡化一下,說一下自己的理解 事件 Event 

觀察模式的程式例項C++ 以及觀察模式事件監聽的區別

一、什麼是觀察者模式      Observer模式也叫觀察者模式,它的作用是當一個物件的狀態發生變化時,可以自己主動通知其它關聯物件,自己主動重新整理物件狀態。 舉個樣例,使用者介面能夠作為一個觀察者,業務資料是被觀察者,使用者介面觀察業務資料的變化,發現數據變化後,

C#】Event事件的應用之觀察模式

using System; namespace Event { // 在遊戲設計中,通常會出現這樣的場景,有一個正在巡邏的敵軍隊伍,當玩家攻擊了其中之一的敵人時 // 那個隊伍的所有敵人都會注意到玩家,並且開始攻擊玩家 // 以下便是個觀察者模式的簡略程式碼

設計模式觀察模式事件委託

        觀察者模式:                 定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某個主題物件。這個主題物件在狀態發生變化時,會通知所有觀察者物件,使它們能夠自己更新自己。           觀察者結構模式圖:               

觀察模式-貓捉老鼠(委託事件

貓捉老鼠是一個典型的觀察者模式的實現案例,在其中加入委託與事件的程式實現,將會提高程式碼的一個可讀性,其下是程式碼實現: 建立一個Cat類: using System; using System.

觀察模式C#實現實例(一)

upd 添加 add mov user remove 定義 更新 鬧鐘 1.用例情景   1)定義一個鬧鐘(目標類),裏面我們感興趣的是時間值times,當times大於9.15時,通知觀察者。   2)定義兩個觀察者,userA,userB,當收到times值時,作出判斷

設計模式——觀察模式C++實現)

ace mes des ret rtu cto pattern virt date 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

C#設計模式--觀察模式(發布-訂閱模式

工廠方法 設計 解決 line strac itl names spa ret 0.C#設計模式--簡單工廠模式 1.C#設計模式--工廠方法模式 2.C#設計模式--抽象工廠模式 3.C#設計模式--單例模式 4.C#設計模式--建造者模式 5.C#設計模式--

Java設計模式補充:回調模式事件監聽器模式觀察模式(轉)

應該 hand 關閉 lan china 關註 update 使用 event 一、回調函數 為什麽首先會講回調函數呢?因為這個是理解監聽器、觀察者模式的關鍵。 什麽是回調函數 所謂的回調,用於回調的函數。 回調函數只是一個功能片段,由用戶按照回調函數調用約定來實現的

事件(_觀察模式

collect cti threading 發布 adk names [] 委托 mouse 一個類如果聲明一個Public的委托讓其他方法註冊,同樣也會存在外部直接調用此委托,這樣是有會出現莫名的調用風險的。因此就有了事件,事件無法在外部直接調用。外部只有註冊(定閱)。內

c#設計模式-觀察模式

正在 pro 描述 設計 abstract logs 名單 ron alt Observer 與 Subject 互為耦合,但是這種耦合的雙方都依賴於抽象,而不依賴於具體。 一、觀察者模式 目的 概述 原理 二、 C#中的觀察者模式 概述 模型與觀察者基類 優點 三、

設計模式學習(二)“觀察模式” (C#)

original pan 學習筆記 pri 接口 program date contain 兩個 《深入淺出設計模式》學習筆記第二章 需求: 開發一套氣象監測應用,如圖: 氣象站,目前有三種裝置,溫度、濕度和氣壓感應裝置。 WeatherData對象追蹤氣象站的數據,並更

設計模式學習(二): 觀察模式 (C#)

模式 album 預報 其中 需求 學習 應用 bsp 要求 《深入淺出設計模式》學習筆記第二章 需求: 開發一套氣象監測應用,如圖: 氣象站,目前有三種裝置,溫度、濕度和氣壓感應裝置。 WeatherData對象追蹤氣象站的數據,並更新到布告板,布告板(目前是三個:目前狀