Effective C# Item22:使用事件定义外发接口
? ? 事件為類型定義了外發接口,C#的事件是建立在委托的基礎上的,委托為事件處理器提供了類型安全的函數簽名。
? ? 委托要比事件的使用范圍廣泛,我們可以把事件看做是一種經過了封裝的委托,專門用于事件驅動模型。你可以在客戶代碼中直接調用委托來激發委托指向的函數,而事件不可以,你只能在服務端調用事件,在客戶端調用事件是會引發編譯錯誤的。我們來看下面的程序。
代碼 1 public class EventTest
2 {
3 public delegate int Add(int value1, int value2);
4 public event Add AddHandler;
5 public Add AddDelegate;
6
7 public void OutputAddResult(int value1, int value2)
8 {
9 AddHandler(value1, value2);
10 }
11 }
12
13 public class ClientTest
14 {
15 private EventTest m_EventTest;
16
17 public ClientTest()
18 {
19 m_EventTest = new EventTest();
20 m_EventTest.AddHandler += new EventTest.Add(m_EventTest_AddHandler);
21 m_EventTest.AddDelegate = AddDelegate;
22 //the line below will cause compile error.
23 //m_EventTest.AddHandler(1, 1);
24 ? m_EventTest.AddDelegate(1, 1);
25 }
26
27 private int m_EventTest_AddHandler(int value1, int value2)
28 {
29 return value1 + value2;
30 }
31
32 private int AddDelegate(int value1, int value2)
33 {
34 return value1 + value2;
35 }
36 } ??? 上述代碼也說明對于委托,你不但可以安排誰是它的調用函數,還可以直接調用它;而對于事件,你是不能直接調用的,只能通過某些操作觸發。
? ? .NET針對Event類型的變量,定義了add和remove兩個訪問器,類似于普通屬性中的get和set,通過add和remove,我們可以使用“+=” 或者 “-=”來注冊事件或者解除事件。關于add和remove,是由編譯器自動為我們生成的,在實際編寫代碼時,我們應該聲明共有事件,然后讓編譯器來為我們創建add和remove訪問器。
??? 在定義事件或者事件所在的類型中,是不需要知道潛在的客戶調用方的信息的,即事件是只能夠在服務器端調用,在客戶端進行注冊實現,但是服務器端是無需知道客戶端的信息的,這兩者是松耦合的。這里所說的服務器端和客戶端,分別表示聲明事件的類型和注冊事件的類型。
??? 當我們的類型包含的事件比較多時,仍然采取為每一個事件定義個一個字段的方式,就變的不可取了,這時,我們可以定義一個事件的容器,在運行時,動態的創建事件對象。其中.NET框架內核在Windows控件子系統中包含有這方面的做法示例。
??? 我們可以查看下面的代碼,使用了容器的方式來保存事件的具體信息。
代碼 1 public class Logger
2 {
3 private static System.ComponentModel.EventHandlerList
4 Handlers = new System.ComponentModel.EventHandlerList();
5
6 static public void AddLogger(
7 string system, AddMessageEventHandler ev )
8 {
9 Handlers[ system ] = ev;
10 }
11
12 static public void RemoveLogger( string system )
13 {
14 Handlers[ system ] = null;
15 }
16
17 static public void AddMsg ( string system,
18 int priority, string msg )
19 {
20 if ( ( system != null ) && ( system.Length > 0 ) )
21 {
22 AddMessageEventHandler l =
23 Handlers[ system ] as AddMessageEventHandler;
24
25 LoggerEventArgs args = new LoggerEventArgs(
26 priority, msg );
27 if ( l != null )
28 l ( null, args );
29
30 // The empty string means receive all messages:
31 l = Handlers[ "" ] as AddMessageEventHandler;
32 if ( l != null )
33 l( null, args );
34 }
35 }
36 } ??? 上述代碼會在EventHandlerList集合中存儲各個事件處理器,當客戶代碼關聯到一個特定的子系統(或者說Key值)時,新的事件對象就會被創建。對于同一個Key值,其后的請求會返回相同的事件對象,因為容器是一個靜態容器。如果我們的類型在其接口中包含有大量的時間,那么我們就應該采用這種事件容易的方式,當客戶代碼真正關聯事件處理器時,我們才會創建事件成員。
?
??? 總結:我們使用事件來定義類型中的外發接口,任意數量的客戶對象都可以將自己的處理器注冊到事件上,然后處理它們,這些客戶對象不需要在編譯時存在,事件也不必非有訂閱者才可以正常工作。在C#中使用事件可以對發送者和可能的通知接收者進行解耦,發送者完全可以獨立于接收者進行開發。
轉載于:https://www.cnblogs.com/wing011203/archive/2010/01/16/1649775.html
總結
以上是生活随笔為你收集整理的Effective C# Item22:使用事件定义外发接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1个多月就能看到效果的减肥大法 - 健康
- 下一篇: 第05篇:C#星夜拾遗之使用数据库