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