1. Define a type which will hold any additional information that should be sent to receivers of the event notification. By convention, types that hold event information are derived from System.EventArgs and the name of the type should end with "EventArgs".
The EventArgs type is inherited from Object and looks like this:
[Serializable]
public class EventArgs {
public static readonly EventArgs Empty = new EventArgs();
public EventArgs() { }
}
It simply serves as a base type from which other types may derive. Many events don't have any additional information to pass on. When you are defining an event that doesn't have any additional data to pass on, just use EventArgs.Empty.
2. Define a delegate type specifying the prototype of the method that will be called when the event fires. By convention, the name of the delegate should end with "EventHandler". It is also by convention that the prototype have a void return value and take two parameters. The first parameter is an Object that refers to the object sending the notification, and the second parameter is an EventArgs-derived type containing any additional information that receivers of the notification require.
If you're defining an event that has no additional information that you want to pass to receivers of the event, then you do not have to define a new delegate.
You can use the System.EventHandler delegate and pass EventArgs.Empty for the second parameter. The prototype of EventHandler is as follows:
public delegate void EventHandler(Object sender, EventArgs e);
3. Define an event.
4. Define a protected, virtual method responsible for notifying registered objects of the event. The OnXXX method is called when a event occurs. This method receives an initialized XXXEventArgs object containing additional information about the event. This method should first check to see if any objects have registered interest in the event and if so, the event should be fired.
This gives the derived type control over the firing of the event. The derived type can handle the event in any way it sees fit. Usually, a derived type will call the base type's OnXXX method so that the registered object will receive the notification. However, the derived type may decide not to have the event forwarded on.
5. Finally, define a method that translates the input into the desired event.
It is also useful to know what compiler does when it sees the event keyword. This also would help us understand why a new type "event" was required. For example, say we have the following line
public event EventHandler MailMsg;
The C# compiler translates this single line of source code into three constructs
1. The first construct is simply a field that is defined in the type. This field is a reference to the head of a linked list of delegates that want to be notified of this event. This field is initialized to null, meaning that no listeners have registered interest in the event.
You'll notice that event fields (MailMsg in this example) are always private even though the original line of source code defines the event as public. The reason for making the field private is to prevent code outside the defining type from manipulating the field improperly.
// A PRIVATE delegate field that is initialized to null
private EventHandler MailMsg = null;
2. The second construct generated by the C# compiler is a method that allows other objects to register their interest in the event. The C# compiler automatically names this function by prepending "add_" to the field's name (MailMsg).
// A PUBLIC add_* method.
// Allows objects to register interest in the event
MethodImplAttribute(MethodImplOptions.Synchronized)]
public void add_MailMsg(EventHandler handler) {
MailMsg = (EventHandler)
Delegate.Combine(MailMsg, handler);
}
3. The C# compiler is a method that allows an object to unregister its interest in the event. Again, the C# compiler automatically names this function by prepending "remove_" to the field's name (MailMsg).
// A PUBLIC remove_* method.
// Allows objects to unregister interest in the event
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void remove_Click (MailMsgEventHandler handler) {
MailMsg = (MailMsgEventHandler)
Delegate.Remove(MailMsg, handler);
}
Other facts that you should know about the events.
1. The thread used when firing the event, is the thread used to handle the event.
2. When an event has multiple subscribers, the event handlers are invoked synchronously when an event is raised.
3. It is necessary to unsubscribe from events to prevent resource leaks. The publisher holds a reference of the subscriber and the garbage collector would not delete the subscriber object until you unsubscribe from the event. So, you should unsubscribe from events before you dispose of a subscriber object.
No comments:
Post a Comment