Friday, January 11, 2013

Standard Way of Writing an Event in C#


In .Net there is a standard pattern to write an event. System.EventArgs is the main player in this pattern. This acts as a base class for conveying message through an event.

EventArgs is a pre-defined class in the .Net Framework with no members other than EventArgs.Empty static member. So let’s see how to create an event in a standard way using the EventArgs.

First of all we need to create a class which is subclassing the EventArgs class. Consider the temperature example in my previous post Delegates and Events in C# :

public class TemperatureChangedEventArgs :EventArgs
{
   public readonly double OldTemperature;
   public readonly double NewTemperature;

   public TemperatureChangedEventArgs(double oldTemp, double newTemp)
  {
     OldTemperature = oldTemp;
     NewTemperature = newTemp;
  }

}

Typically the EventArgs class exposes the data as either a read only field or as a property. Define what all information required to pass along with the event as a property or read only field. In this example, whenever the temperature change event occurs, along with the event, we need to pass the old temperature and new temperature. So those data are stored as read only fields in the EventArgs subclass. The constructor of the class should accept the required information and then assign it to the EventArgs class members.

Now we have our EventArgs subclass in place. Now we need to define a delegate for the event. The delegate should meet the following rules:

1. The return type should be void
2. The name of the delegate should end with EventHandler
3. The event should accept 2 arguments - one is the instance of the broadcaster and second one is the instance of the EventArgs subclass.

So we need to create a delegate like:

public delegate void TemperatureChangedEventhandler(object sender,
TemperatureChangedEventArgs e);

In .Net Framework there is a generic delegate which matches this criteria EventHandler<>.

So let’s now rewrite our TemperatureBroadcaster class from the previous post Delegates and Events in C# :

Three things to take care while writing the class
1. Create an Event using the EventHandler<>.
      public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged; 

2.  Create a protected virtual method which invokes the event. The name of the method should be like appending an On with the event instance name.

    protected virtual void OnTemperatureChanged(TemperatureChangedEventArgs e)
    {
      if (TemperatureChanged != null)
      {
        TemperatureChanged(this, e);
      }
    }

3. Call the protected virtual method from the set accesser of the changing property, Temperature property in our case.
   
     OnTemperatureChanged(new TemperatureChangedEventArgs(oldTemperature, temperature));

So this is how our TemperatureBroadcaster class looks like:

public class TemperatureBroadcaster
{

  //EventHandler<> is a generic delegate which satisfies the rules mentioned earlier.
  public event EventHandler<TemperatureChangedEventArgs> TemperatureChanged;
  double temperature;

  public TemperatureBroadcaster()
  {
  }

  // The protected virtual void method which invokes the event.
  protected virtual void OnTemperatureChanged(TemperatureChangedEventArgs e)
  {
    if (TemperatureChanged != null)
    {
      TemperatureChanged(this, e);
    }
  }

  public double Temperature
  {
    get
    {
      return temperature;
    }
    set
    {
      if (temperature == value)
      return;
      double oldTemperature = temperature;
      temperature = value;
      //calling the method to invoke the event when the temperature is changed.
      OnTemperatureChanged(new TemperatureChangedEventArgs(oldTemperature, temperature));
    }
  }

}

If in your case you don’t need to pass any information along with the event, then you can use the EventArgs.Empty as the parameter. This will avoid unnecessary instance creation of the EventArgs Subclass

 //Use the pre-defined EventHandler
 public event EventHandler TemperatureChanged;

//change the protected method to accept EventArgs as parameter
protected virtual void OnTemperatureChanged(EventArgs e)
{
  if (TemperatureChanged != null)
  {
    TemperatureChanged(this, e);
  }
}

// from the set accessor of the changing property, pass EventArgs.Empty
OnTemperatureChanged(EventArgs.Empty);


I hope this post was helpful for you. Thanks for reading by blog.

                                                                                                               --Ratheesh Rahulan


No comments:

Post a Comment