CSharp(C#)語言_第十二章(事件)

12.1 發佈者和訂閱者

  很多程序都有一個共同的需求,即當一個特定的程序事件發生時,程序的其他部分可以得到該事件已經發生的通知
  發佈者/訂閱者模式(publisher/subscriber pattern)可以滿足這種需求。在這種模式中,發佈者類定義了一系列程序的其他部分可能感興趣的事件。其他類可以“註冊”,以便在這些事件發生時發佈者可以通知它們。這些訂閱者類通過向發佈者提供一個方法來“註冊”以獲取通知。當事件發生時,發佈者“觸發事件”,然後執行訂閱者提交的所有事件
  由訂閱者提供的方法稱爲回調方法,因爲發佈者通過執行這些方法來“往回調用訂閱者的方法”。還可以將它們稱爲事件處理程序,因爲它們是爲處理事件而調用的代碼

ps:
事件
注意

  • 發佈者(publisher) 發佈某個事件的類或結構,其他類可以在該事件發生時得到通知
  • 訂閱者(subscriber) 註冊並在事件發生時得到通知的類或結構。
  • 事件處理程序(event handler) 由訂閱者註冊到事件的方法,在發佈者觸發事件時執行。事件處理程序方法可以定義在事件所在的類或結構中,也可以定義在不同的類或結構中
  • 觸發(raise)事件 調用(invoke)或觸發(fire)事件的術語。當事件觸發時,所有註冊到它的方法都會被依次調用

12.2 源代碼組件概覽

需要在事件中使用的代碼有5部分

  • 委託類型聲明 事件和事件處理程序必須有共同的簽名和返回類型,它們通過委託類型進行描述
  • 事件處理程序聲明 訂閱者類中會在事件觸發時執行的方法聲明。它們不一定是有顯式命名的方法,還可以是匿名方法或Lambda表達式
  • 事件聲明 發佈者類必須聲明一個訂閱者類可以註冊的事件成員。當聲明的事件爲public時,稱爲發佈了事件
  • 事件註冊 訂閱者必須訂閱事件才能在它被觸發時得到通知
  • 觸發事件的代碼 發佈者類中“觸發”事件並導致調用註冊的所有事件處理程序的代碼
    ps:
    需要在事件中使用的代碼有5部分

12.3 聲明事件

  發佈者類必須提供事件對象。創建事件比較簡單——只需要委託類型和名字。事件聲明的語法如下代碼所示,代碼中聲明瞭一個叫做CountADozen的事件。注意如下有關CountedADozen事件的內容

  • 事件聲明在一個類中
  • 它需要委託類型的名稱,任何附加到事件(如註冊)的處理程序都必須與委託類型的簽名和返回類型匹配
  • 它聲明爲public,這樣其他類和結構可以在它上面註冊事件處理程序
  • 不能使用對象創建表達式(new表達式)來創建它的對象
class Incrementer
{
	//實例事件
	//	   關鍵字	委託類型	    事件名
	public event EventHandler CountedADozen;
//或
	public event EventHandler MyEvent1,MyEvent2,MyEvent3;
	
	//靜態事件
	public static event EventHandler CountedADozen;
}

事件是成員
事件和方法、屬性一樣。是類或結構的成員

重要特性

  • 由於事件是成員:
    • 我們不能在一段可執行代碼中聲明事件
    • 它必須聲明在類或結構中,和其他成員一樣
  • 事件成員被隱式自動初始化爲null

  事件聲明需要委託類型的名字,我們可以聲明一個委託類型或使用已存在的。如果我們聲明一個委託類型,它必須指定事件保存的方法的簽名和返回類型

12.4 訂閱事件

訂閱者向事件添加事件處理程序。對於一個要添加到事件的事件處理程序來說,它必須具有與事件的委託相同的返回類型和簽名

  • 使用 += 運算符來爲事件增加事件處理程序,如下面代碼所示。事件處理程序位於該運算符的右邊。
  • 事件處理程序的規範可以是以下任意一種:
    • 實例方法的名稱
    • 靜態方法的名稱
    • 匿名方法
    • Lambda表達式

eg: 爲 CountedADozen 事件添加方法

// 類			事件成員				實例方法
incrementer.CountedADozen += IncrementOozensCount; //方法引用形式
//								靜態方法
incrementer.CountedADozen += ClassB.CountexHandlerB; //方法引用形式

// 委託形式
mc.CountedADozen += new EventHandler(cc.CounterHandlerC); 

// Lambda表達式
incrementer.CountedADozen +=(=> DozensCount++;

// 匿名方法
incrementer.CountedADozen += delegate(DozensCount++;};

12.5 觸發事件

事件成員本身只是保存了需要被調用的事件處理程序。如果事件沒有被觸發,什麼都不會發生。我們需要確保在合適的時候有代碼來做這件事情
例如,如下代碼觸發了 CountedADozen 事件。注意如下有關代碼的事項

  • 在觸發事件之前和 null 進行比較,從而查看是否包含事件處理程序,如果事件是null,則表示沒有,不能執行
  • 觸發事件的語法和調用方法一樣:
    • 使用事件名稱,後面跟的參數列表包含在圓括號中
    • 參數列表必須與事件的委託類型相匹配
if (CountedADozen != null) // 確認有方法可以執行
{
	CountedADozen(source,args); // 觸發事件
}

移除事件處理程序
  在用完了事件處理程序之後,可以從事件中把它移除。可以利用-=運算符把事件處理程序從事件中移除,如下所示:

p.SimpleEvent -= s.MethodB; //移除事件處理程序HethodB

12.6 事件訪問器

  • 有兩個訪問器:add和remove
  • 聲明事件的訪問器看上去和聲明一個屬性差不多
public event EventHandler CountedADozen
{
	add
	{
		... 	//執行+=運算符的代碼
	}
	remove
	{ 
		...		//執行-=運算符的代碼
	} 
}

  聲明瞭事件訪問器之後,事件不包含任何內嵌委託對象。我們必須實現自己的機制來存儲和移除事件註冊的方法
  事件訪問器表現爲 void 方法,也就是不能使用包含返回值的 return 語句

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章