用 C# 做組件設計時的事件實現方法討論

來源:互聯網
上載者:User

事件,其實就是將物體的某個過程處理通過委託(delegate, 也就是函數指標) 的方式公開給外部的自訂函數處理。 C# 可以使用多播委託,但實際上一般情況下只需要用到單播。

事件需要通過調用到那個委託的代碼觸發才可以被調用。
以下用例子來說明。首先我們定義一個委託:

namespace EventDemo{public delegate void ProcessHandler(object sender);}

最簡單的事件定義方式:

namespace EventDemo{public class Class1{private event ProcessHandler _processHandler = null;public event ProcessHandler ProcessStart{add { _processHandler += value; }remove { _processHandler -= value; }}/// /// 觸發事件的某個方法/// public void Process(){_processHandler(this);for (int i = 0; i < 10; i++)i = i + 1;}public Class1(){}}}

Class1 使用原始的事件定義方式, 有一個問題,如果事件非常多的時候,每一個事件都要對應一個相應的私人的委託成員(函數指標)。在視窗程序裡尤其可怕,因為 Windows 視窗訊息數以千計。這樣會造成很龐大的記憶體消耗。
這個模式需要改進為 Class2。代碼如下:

namespace EventDemo{using System.Collections;public class Class2{private Hashtable _eventList = new Hashtable();// 每一種事件會對應一個相應的靜態變數作為他們在 Hashtable 中的 keys.private static object _processStart = new object();private static object _processEnd = new object();public event ProcessHandler ProcessStart{add { _eventList.Add(_processStart, value); }remove { _eventList.Remove(_processStart); }}public event ProcessHandler ProcessEnd{add { _eventList.Add(_processEnd, value); }remove { _eventList.Remove(_processEnd); }}public void Process(){ProcessHandler start = (ProcessHandler) _eventList[_processStart];ProcessHandler end = (ProcessHandler) _eventList[_processEnd];if (start != null)start(this);for (int i = 0; i < 10; i++)i = i + 1;if (end != null)end(this);}public Class2(){}}}

Class2 中,每一種事件定義一個相應的靜態變數作為他們在 Hashtable 中的 keys.
Hashtable 作為函數指標的容器,是私人的。
這樣實際上是 Lazy Allocate 模式,大大減小了記憶體的開銷。
但該實現也有問題,因為每個 key 只對應一個 value,所以不能支援 multicast 的事件。

在 .net 中,通常繼承自 Component 類來實現這種基礎架構。代碼如下:

namespace EventDemo{using System;using System.ComponentModel;public class Class3 : Component{private static object _processStart = new object();public event EventHandler ProcessStart{add { Events.AddHandler(_processStart, value); }remove { Events.RemoveHandler(_processStart, value); }}public void Process(){EventHandler handler = (EventHandler) Events[_processStart];if (handler != null)handler(this, null);}public Class3(){}}}

Component 類的實現是完整的,支援 Multicast 委託。我們用 Reflector 看一下該類的代碼,會看到有一個叫做 EventHandlerList 的類,代碼如下:

public sealed class EventHandlerList : IDisposable{// Methodspublic EventHandlerList(){}public void AddHandler(object key, Delegate value){EventHandlerList.ListEntry entry1 = this.Find(key);if (entry1 != null){entry1.handler = Delegate.Combine(entry1.handler, value);}else{this.head = new EventHandlerList.ListEntry(key, value, this.head);}}public void Dispose(){this.head = null;}private EventHandlerList.ListEntry Find(object key){EventHandlerList.ListEntry entry1 = this.head;while (entry1 != null){if (entry1.key == key){break;}entry1 = entry1.next;}return entry1;}public void RemoveHandler(object key, Delegate value){EventHandlerList.ListEntry entry1 = this.Find(key);if (entry1 != null){entry1.handler = Delegate.Remove(entry1.handler, value);}}// Propertiespublic Delegate this[object key]{get{EventHandlerList.ListEntry entry1 = this.Find(key);if (entry1 != null){return entry1.handler;}return null;}set{EventHandlerList.ListEntry entry1 = this.Find(key);if (entry1 != null){entry1.handler = value;}else{this.head = new EventHandlerList.ListEntry(key, value, this.head);}}}// Fieldsprivate ListEntry head;// Nested Typesprivate sealed class ListEntry{// Methodspublic ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next){this.next = next;this.key = key;this.handler = handler;}// Fieldsinternal Delegate handler;internal object key;internal EventHandlerList.ListEntry next;}}

這個類實現了一個事件的鏈表資料結構。其中每一個具體的事件是採用 Delegate.Combine(), Delegate.Remove() 方法來添加和刪除具體的 delegate. 所以這個的實現和 Class2 的實現相比功能更加完整了。

Component 類的代碼是這樣的:

[DesignerCategory("Component")]public class Component : MarshalByRefObject, IComponent, IDisposable{private EventHandlerList events;protected EventHandlerList Events{get{if (this.events == null){this.events = new EventHandlerList();}return this.events;}}// ...}

它簡單的通過提供 Events 這個屬性,讓設計者可以自由的實現各種屬性。

(註:本文的 Class1 ~ Class3 代碼範例來自黃忠成的《深入剖析 asp.net 組件設計》一書。)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.