Friday, 24 January 2014

Events and delegates in C#

Delegates

A delegate is a reference type, but instead of referring to an object, a delegate refers to a method. In other words, a delegate is a type that represents references to methods with a particular parameter list and return type.  This is called encapsulating the method. When you create the delegate, you specify a method signature and return type; you can encapsulate any matching method with that delegate. It is like a function pointer in C++ but are type safe (the method passed needs to conform to the method signature).
You create a delegate with the delegate keyword, followed by a return type and the signature of the methods that can be delegated to it, as in the following:
public delegate int FindResult(object obj1, object obj2);
class MediaStorage {
  public delegate int PlayMedia();
  public void ReportResult(PlayMedia playerDelegate)
  {
    if (playerDelegate( ) == 0)
    {
        Console.WriteLine("Media played successfully.");
    }
    else
    {
        Console.WriteLine("Media did not play successfully.");
    }
  }
}
public class AudioPlayer
{
    private int audioPlayerStatus;

    public int PlayAudioFile( )
    {
        Console.WriteLine("Simulating playing an audio file here.");
        audioPlayerStatus = 0;
        return audioPlayerStatus;
    }
}

MediaStorage myMediaStorage = new MediaStorage( );
// instantiate the delegates
// PlayAudioFile conforms to the PlayMedia delegate signature
MediaStorage.PlayMedia audioPlayerDelegate = new
                   MediaStorage.PlayMedia(myAudioPlayer.PlayAudioFile);
myMediaStorage.ReportResult(audioPlayerDelegate);
Events and Delegates
class Clock {
// Define the SecondChangedHandler delegate type. This delegate will encapsulate any method that
// returns void and that takes two parameters. 
public delegate void SecondChangeHandler(
    object clock, TimeInfoEventArgs timeInformation);
// Create an instance of the delegate
public SecondChangeHandler SecondChanged;
}
class DisplayClock {
public void Subscribe(Clock theClock)
{
  theClock.SecondChanged +=
    new Clock.SecondChangeHandler(WriteLogEntry);
}
}
The problem with the above code snippet is that other methods can call SecondChanged directly and this is not normally the original class intends..  For example:
Console.WriteLine("Calling the method directly!");
System.DateTime dt = System.DateTime.Now.AddHours(2);
TimeInfoEventArgs timeInformation =
    new TimeInfoEventArgs(  dt.Hour,dt.Minute,dt.Second);
theClock.SecondChanged(theClock, timeInformation);
To prevent external calls to the delegated method directly, one can make the delegate private, but then this will prevent clients from registering with the delegate at all. What's needed is a way to say, "This delegate is designed for event handling: you may subscribe and unsubscribe, but you may not invoke it directly."


To fix your program, change your definition of SecondChanged from:
public SecondChangeHandler SecondChanged;
to the following:
public event SecondChangeHandler SecondChanged;
Adding the event keyword fixes both problems. Classes can no longer attempt to subscribe to the event using the assignment operator (=), as they could previously, nor can they invoke the event directly, as was done in the preceding example. Either of these attempts will now generate a compile error.

There are two ways of looking at SecondChanged now that you've modified it. In one sense, it is simply a delegate instance to which you've restricted access using the keyword event. In another, more important sense,SecondChanged is an event, implemented by a delegate of type SecondChangeHandler. These two statements mean the same thing, but the latter is a more object-oriented way of looking at it, and better reflects the intent of this keyword: to create an event that your object can raise, and to which other objects can respond.
You can also assign this delegate by writing the shortened version:
theClock.SecondChanged += TimeHasChanged;
Reference:
http://msdn.microsoft.com/en-us/library/orm-9780596521066-01-17.aspx
http://msdn.microsoft.com/en-us/library/ms173171.aspx

No comments :

Post a Comment