Back when I was learning C#, I was taught a pattern for events that went something like this:
public class Tribe
{
// For demonstration only. Please do not write code like this.
public class TribesmanAddedEventArgs : EventArgs
{
private readonly Tribesman _tribesman;
public TribesmanAddedEventArgs(Tribesman tribesman)
{
_tribesman = tribesman;
}
public Tribesman NewTribesman
{
get { return _tribesman; }
}
}
public delegate void TribesmanAddedDelegate(object sender, TribesmanAddedEventArgs args);
public event TribesmanAddedDelegate TribesmanAdded;
private void OnTribesmanAdded(Tribesman tribesman)
{
if(TribesmanAdded != null)
TribesmanAdded(this, new TribesmanAddedEventArgs(tribesman));
}
}
Needless to say, this is a pretty awful pattern. Add a few more events to this class (TribesmanRemoved, TribesmanModified, etc) and your code becomes a complete mess really quickly.
With some of the advances that C# language has made, and the EventHandler<> generic delegate, we can thankfully clean this up a bit:
public class Tribe
{
public class TribesmanAddedEventArgs : EventArgs
{
public TribesmanAddedEventArgs(Tribesman tribesman)
{
NewTribesman = tribesman;
}
public Tribesman NewTribesman { get; private set; }
}
public event EventHandler<TribesmanAddedEventArgs> TribesmanAdded;
private void OnTribesmanAdded(Tribesman tribesman)
{
if(TribesmanAdded != null)
TribesmanAdded(this, new TribesmanAddedEventArgs(tribesman));
}
}
Can we take this any further? You bet. The EventArgs classes tend to be very boilerplate. Lets generalize it so we only have to write this code once:
public class EventArgs<PayloadType> : EventArgs
{
public EventArgs(PayloadType payload)
{
Payload = payload;
}
public PayloadType Payload { get; private set; }
}
Now that we have that out of the way, the event pattern can be drastically reduced:
public class Tribe
{
public event EventHandler<EventArgs<Tribesman>> TribesmanAdded;
private void OnTribesmanAdded(Tribesman tribesman)
{
if(TribesmanAdded != null)
TribesmanAdded(this, new EventArgs<Tribesman>(tribesman));
}
}
This code is really starting to look better. Next, through the magic of extension methods, we can eliminate the "OnTribesmanAdded" method as well:
public static class EventExtensions
{
public static void Fire<T>(this EventHandler<EventArgs<T>> handler, object sender, T payload)
{
if(handler != null)
handler(sender, new EventArgs<T>(payload));
}
}
There we go! Now, anywhere in the class that you want to fire the event, you can just call TribesmanAdded.Fire(this, newTribesman) and not worry if the event has been subscribed to. This is a case where you can call a method on a null object safely, because "Fire" is actually a static method. Even better, the event code in our class can be reduced to this:
public class Tribe
{
public event EventHandler<EventArgs<Tribesman>> TribesmanAdded;
}
In my opinion, this is the way we should be writing events in C# 3.0 and beyond. What do you think?