Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   How the Compiler Implements an Event

Now that you know how to define a class that offers an event member, let’s take a closer look at what an event really is and how it works. In the MailManager class, we have a line of code that defines the event member itself.

 

public event EventHandler<NewMailEventArgs> NewMail;

 

When the C# compiler compiles the line above, it translates this single line of source code into the following three constructs.

 

// 1. A PRIVATE delegate field that is initialized to null private EventHandler<NewMailEventArgs> NewMail = null;

 

// 2. A PUBLIC add_Xxx method (where Xxx is the Event name)

// Allows methods to register interest in the event.

public void add_NewMail(EventHandler<NewMailEventArgs> value) {

// The loop and the call to CompareExchange is all just a fancy way

// of adding a delegate to the event in a thread­safe way EventHandler<NewMailEventArgs>prevHandler;


EventHandler<NewMailEventArgs> newMail = this.NewMail; do {

prevHandler = newMail; EventHandler<NewMailEventArgs> newHandler =

(EventHandler<NewMailEventArgs>) Delegate.Combine(prevHandler, value); newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>(

ref this.NewMail, newHandler, prevHandler);

} while (newMail != prevHandler);

}

 

// 3. A PUBLIC remove_Xxx method (where Xxx is the Event name)

// Allows methods to unregister interest in the event.

public void remove_NewMail(EventHandler<NewMailEventArgs> value) {

// The loop and the call to CompareExchange is all just a fancy way

// of removing a delegate from the event in a thread­safe way EventHandler<NewMailEventArgs> prevHandler; EventHandler<NewMailEventArgs> newMail = this.NewMail;

do {

prevHandler = newMail; EventHandler<NewMailEventArgs> newHandler =

(EventHandler<NewMailEventArgs>) Delegate.Remove(prevHandler, value); newMail = Interlocked.CompareExchange<EventHandler<NewMailEventArgs>>(

ref this.NewMail, newHandler, prevHandler);

} while (newMail != prevHandler);

}

 

The first construct is simply a field of the appropriate delegate type. This field is a reference to the head of a list of delegates that will be notified when this event occurs. This field is initialized to null, meaning that no listeners have registered interest in the event. When a method registers interest in the event, this field refers to an instance of the EventHandler<NewMailEventArgs> delegate, which may refer to additional EventHandler<NewMailEventArgs> delegates. When a listener registers in- terest in an event, the listener is simply adding an instance of the delegate type to the list. Obviously, unregistering means removing the delegate from the list.

You’ll notice that the delegate field, NewMail in this example, is always private even though the original line of source code defines the event as public. The reason for making the delegate field private is to prevent code outside the defining class from manipulating it improperly. If the field were public, any code could alter the value in the field and potentially wipe out all of the delegates that have registered interest in the event.



The second construct the C# compiler generates 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 event’s name (NewMail). The C# compiler automatically generates the code that is inside this method. The code always calls System.Delegate’s static Combine method, which adds the instance

of a delegate to the list of delegates and returns the new head of the list, which gets saved back in the

field.

 

The third construct the C# compiler generates 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 event’s name (NewMail). The code inside this method always calls Delegate’s static Remove method, which removes the instance of a delegate from the list of delegates and returns the new head of the list, which gets saved back in the field.


       
   
 

 

In this example, the add and remove methods are public. The reason they are public is that the original line of source code declared the event to be public. If the event had been declared protected, the add and remove methods generated by the compiler would also have been de- clared protected. So, when you define an event in a type, the accessibility of the event determines what code can register and unregister interest in the event, but only the type itself can ever access the delegate field directly. Event members can also be declared as static or virtual, in which case the add and remove methods generated by the compiler would be either static or virtual, respectively.

In addition to emitting the aforementioned three constructs, compilers also emit an event defini- tion entry into the managed assembly’s metadata. This entry contains some flags and the underly- ing delegate type, and refers to the add and remove accessor methods. This information exists simply to draw an association between the abstract concept of an “event” and its accessor methods. Compilers and other tools can use this metadata, and this information can also be obtained by us- ing the System.Reflection.EventInfo class. However, the CLR itself doesn’t use this metadata information and requires only the accessor methods at run time.

 


Date: 2016-03-03; view: 660


<== previous page | next page ==>
Notify registered objects that the event has occurred | Nbsp;   Designing a Type That Listens for an Event
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.011 sec.)