Optimizing Event Implementation


We'll now digress from the main topic to show you a more efficient way to implement events in server controls. In Chapter 3, we mentioned that if a class raises many events, it is not efficient to implement them by declaring an event member for each event as we did in SimpleButton . Let's examine why and look at a more optimal implementation.

Note

The optimized event implementation relies on the event property construct, which is not available in Microsoft Visual Basic .NET.


There are two reasons why it is not efficient to declare an event member for each event. First, when you declare an event member such as public event EventHandler Click , the compiler generates a private field of type delegate for that event, such as private EventHandler Click . In Chapter 3, we looked at that field using the ILDASM disassembler tool. The delegate field is created for each event declared by the class, irrespective of whether any event handlers are attached to the event in user code. This is an inefficient use of memory, especially if your control raises a large number of events.

Second, the compiler-generated add and remove methods are marked as synchronized for thread safety, which means they acquire a lock every time a user adds or removes a delegate from the event. Locks add unnecessary overhead because page developers rarely use multithreading on a single page.

We'll now examine a more efficient event implementation pattern in the .NET Framework that uses the System.ComponentModel.EventHandlerList class, which is a linked list optimized for the storage and retrieval of delegates. Let's see how the base Control class implements events by using the optimized event pattern. The Control class defines a property named Events of type EventHandlerList :

 privateEventHandlerList_events; protectedEventHandlerListEvents{ get{ if(_events==null){ _events=newEventHandlerList(); } return_events; } } 

The Control class defines a key for each event, which it uses to store and retrieve event delegates in the EventHandler . The following code shows the key for the Init event:

 protectedstaticreadonlyobjectEventInit=newobject(); 

The key is static (shared across all instances of the control) and thus is created only once for each event.

Instead of using event fields, the Control class uses the event property construct to define events. The C# event property construct is illustrated in the following code, which shows the declaration of the Init event in the Control class:

 publiceventEventHandlerInit{ add{ Events.AddHandler(EventInit,value); } remove{ Events.RemoveHandler(EventInit,value); } } 

Whenever user code adds or removes a delegate from an event, the control instance adds or removes the delegate from the EventHandler list by using the key for that event (such as EventInit ). Under the hood, the EventHandler instance performs one of the following tasks when its AddHandler method is invoked:

  • If there is no delegate corresponding to the key, the EventHandler instance adds the delegate as a new list element.

  • If a delegate already exists in the list corresponding to the key, EventHandler uses the Combine method of the Delegate class to add the new delegate to the existing delegate.

The RemoveHandler method of the instance works in a similar way, except that it invokes the Remove method of the Delegate class to remove a delegate from an existing delegate. If there is no delegate in the list corresponding to the key, the RemoveHandler method does nothing.

Unlike the event field construct that we used in SimpleButton , the event property construct never creates a delegate field for each event. Memory is allocated for event keys (which are static and created only once for each event that the class defines) and for the EventHandlerList . As we mentioned earlier, another important benefit is that the add and remove methods of EventHandler ­List are not automatically marked as synchronized and therefore do not acquire locks when adding or removing delegates. Event properties implemented by using EventHandlerList do involve lookup but, on the whole, lead to better performance than event fields because they use less memory and do not have the synchronization overhead.

One final detail in the event property construct is the implementation of the On < EventName > method that raises an event. When you use an event property, you must retrieve the delegate from the EventHandlerList and cast it to the type of your event delegate before invoking the attached handlers:

 protectedvirtualvoidOnInit(EventArgse){ EventHandlerinitHandler=(EventHandler)Events[EventInit]; if(initHandler!=null){ initHandler(this,e); } } 

If you author your controls in C#, you should use the optimized event pattern as the samples throughout the rest of this book do.



Developing Microsoft ASP. NET Server Controls and Components
Developing Microsoft ASP.NET Server Controls and Components (Pro-Developer)
ISBN: 0735615829
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net