Events for Confused Beginners - CodeProject

:

 

Introduction

If you are a beginner .NET developer and you have trouble working with events - like me -, then this tip is for you. After immersing myself in articles and videos that address events in .NET, I managed to summarize these articles in a way that helped me understand its structure and hopefully, it will help you as well.

Background

Event is the way used by .NET to notify subscribers about a change or action in the event owner class. As shown in the following graph, the event owner will raise the event without knowing (or caring) about the subscribers. Once raised, .NET will send the notification for each subscriber. The subscriber should create an event handle. Event handle is simply a function that will be run whenever the event is raised.

Using the Code

The events in .NET are based on the delegate structure. Delegate is a pointer to one or more functions that will be called together as in the following snippet.

//The function will write to the string to a file
static void WriteToFile(string s){
    File.Append(s); // a pseudo code
}

//Write to log
static void WriteToLog(string s){
    log.info(s);
}

delegate void writeDelegate(string x); //Define the delegate signature

//Our lovely main function
static void Main(string[] args){

//define a variable of type writeDelegate and hook it the WriteToFile function
//The function must have the same signature as the delegate 
//(return void and accept one parameter of type string in our case)
    writeDelegate x = WriteToFile;
    x+= WriteToLog; //Hook the second function
    x+= (a) => Console.WriteLine(a); //We can also use lambda expression 
    
    //This line will call the 3 functions
    x("Hello World!");
}

So the old way to define an event is by creating a delegate, then define an event based on this delegate and finally raise the event. The following code raises event if the salary is more than 1000.

class Person{
     public delegate void SalaryLimit(int s); //Define the delegate
     public event SalaryLimit IamRich; //Define the event

     private int salary;
     public int Salary{
           get {return salary;}
           set {
                   salary = value;
                   if (salary > 1000){
                         if (IamRich != null){ //an exception will be raised if there are no subscribers
                              IamRich(salary);
                         }
                   }
               }
     }
}

Instead of defining a custom delegate, we can directly use EventHandler and EventHandler<TEventArgs>, These are two predefined delegates with a slightly different signature that can be used with events. The first is usually used if there is no data to pass with the event as follows:

class Person{
public event EventHandler TimeToSleep;
if (time is late){
      if (TimeToSleep != null) {
               TimeToSleep(this, Eventargs.Empty)
       }
}
}

If we want to pass data to subscribers along the event, we have to use EventHandler<TEventArgs> after creating a new class that inherits from EventArgs and add your parameter.

class  AddressEventArgs: EventArgs {
         public string Address {get; set;}
}

Now define your event as follows:

class Person{
       public event EventHandler<AddressEventArgs> AddressChange;
       private string address;
       public string Address{
                  get { return address;}
                  set { address = value;
                                         AddressEventArgs e = new AddressEventArgs();
                                         e.Address = address;
//Instead of calling the event directly, I will use the protected virtual onEvent method 
//as per MSDN guide
                                         onAddressChange(e);
                        }
                       }
                        
           protected virtual void onAddressChange(AddressEventArgs e){
                       EventHandler<AddressEventArgs> handler = AddressChange;
                       if (handler != null){
                             handler(this, e);
                      }
             }
}

On the other hand, the subscribers have to create an event handle which might be a function or a lambda expression. This handle will be called whenever the event is raised.

static void Main(string[] args){
        Person p = new Person();
        // using lambda expression, C# is smart enough to infer the type of o and e;
        p.AddressChange += (o, e) => Console.WriteLine("My new address is " + e.Address);
        // using a function
        p.AddressChange += p_addressChange;
}

static void p_addressChange(object o, AddressEventArgs e){
        Console.WriteLine("My new address is " + e.Address);

}

Conclusion

This is my first tip here, hopefully I will get constructive feedback to enhance it. Thanks for your time.

History

  • March 15, 2015: Initial version
  • March 20, 2015: add the source code and fix some spell errors