An event is actually to expose a process of an object to an external user-defined function through a delegate (delegate, that is, a function pointer. C # You can use multicast delegation, but generally you only need to use unicast.
The event must be called to the Delegate'sCodeTo be called.
The following is an example. First, we define a delegate:
Namespace eventdemo {Public Delegate void processhandler (Object sender );}
The simplest way to define events:
Namespace eventdemo {public class class1 {private event processhandler _ processhandler = NULL; public event processhandler processstart {Add {_ processhandler + = value;} remove {_ processhandler-= value ;}} ////// Method for triggering the event ///Public void process () {_ processhandler (this); For (INT I = 0; I <10; I ++) I = I + 1;} public class1 () {}}}
Class1 uses the original event definition method. If there are many events, each event corresponds to a private delegate member (function pointer ). In the windowProgramWindows has thousands of messages. This will cause a large amount of memory consumption.
This mode needs to be improved to class2. The Code is as follows:
namespace eventdemo {using system. collections; public class class2 {private hashtable _ eventlist = new hashtable (); // each event corresponds to a corresponding static variable as their keys in hashtable. 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 () {}}
In class2, each event defines a corresponding static variable as their keys in hashtable.
Hashtable is a private container for function pointers.
This is actually the lazy allocate mode, which greatly reduces the memory overhead.
However, this implementation is also problematic because each key corresponds to only one value, so multicast events cannot be supported.
In. net, the infrastructure is generally inherited from the component class. The Code is as follows:
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 (){}}}
The implementation of the component class is complete and supports multicast delegation. Let's take a look at the code of this class with reflector. We will see a class called eventhandlerlist. The Code is as follows:
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 ;}}
This class implements an eventLinked ListData structure. Each specific event uses delegate. combine (), delegate. remove () method to add and delete a specific delegate. therefore, this implementation is more complete than the implementation of class2.
The component class code is as follows:
[Designercategory ("component")] public class component: externalbyrefobject, icomponent, idisposable {private eventhandlerlist events; protected eventhandlerlist events {get {If (this. events = NULL) {This. events = new eventhandlerlist ();} return this. events ;}}//...}
It simply provides the events attribute, allowing the designer to freely implement various attributes.
(Note: class1 ~ in this article ~ Class3 code example is from Huang zhongcheng's in-depth analysis of Asp.net component design .)