When you want to create custom events, often you need to pass an event argument, and as often you need only to pass in one parameter - your object.
So what you used to do is:
public event MyCustomEventHandler MyCustomEvent;
public delegate void MyCustomEventHandler(MyCustomEventArg evt);
public class MyObject
{
public string foo;
public int count;
public DateTime when;
public MyObject()
{
foo = "hello world";
count = 42;
when = DateTime.Now;
}
public override string ToString()
{
return string.Format("{0}\t{1}\t{2}",foo,count,when);
}
}
public class MyCustomEventArg : EventArgs
{
private MyObject _value;
public MyObject Data
{
get { return _value; }
set { _value = value; }
}
public MyCustomEventArg(MyObject value)
{
_value = value;
}
}
The not so pretty thing about it is that you had to mind-numbingly create a class which derives from EventArgs just to be able to pass your single event argument MyObject.
Now come generics and Microsoft has provided the generic type:
EventHandler<TEventArgs>
and with it, you can now code
public event EventHandler<MyCustomEventArgs> MyCustomEvent;
// Not "necessary" anymore..
// public delegate void MyCustomEventHandler(MyCustomEventArg evt);
public class MyObject
{...}
public class MyCustomEventArg : EventArgs
{
private MyObject _value;
public MyObject Data
{
get { return _value; }
set { _value = value; }
}
public MyCustomEventArg(MyObject value)
{
_value = value;
}
}
Well, that saved me one line of code! I can ditch work early today :-)
Wouldn't it by nice if I could cut out the whole MyCustomEventArg class? that would save some more lines of code,
and prevent my head from hitting the desk and busting my skull on an upside-down thumb tack.
Well, that's pretty easy to do: create a new class using generics. It supports a single object as a parameter which
can be passed in at construction.
using System;
/// <summary>
/// Encapsulates a single object as a parameter for simple event argument passing
/// <remarks>Now you can declare a simple event args derived class in one wrap</remarks>
/// <code>public void delegate MyCustomeEventHandler(TypedEventArg<MyObject> theSingleObjectParameter)</code>
/// </summary>
public class TypedEventArg<T> : EventArgs
{
private T _Value;
public TypedEventArg(T value)
{
_Value = value;
}
public T Value
{
get { return _Value; }
set { _Value = value; }
}
}
Now the code can look like
public event MyCustomEventHandler MyCustomEvent;
public delegate void MyCustomEventHandler(TypedEventArg<MyObject> evt);
public class MyObject
{ ... }
//This whole thing now goes away..
//public class MyCustomEventArg : EventArgs
//{
// private MyObject _value;
// public MyObject Data
// {
// get { return _value; }
// set { _value = value; }
// }
// public MyCustomEventArg(MyObject value)
// {
// _value = value;
// }
//}
And life is good. I do have to declare the delegate though, so you daring enough to type 2 nested angled brackets, you can go for the gold:
public event EventHandler<TypedEventArg<MyObject>> MyCustomEvent;
//public delegate void MyCustomEventHandler(TypedEventArg<MyObject> evt);
public class MyObject
{ ... }
This lets you dispense with 1 extra line of code so for those of us typing with 1 or 2 fingers, life is better. Readability of nested generic references vs. the declaration of a delegate is a matter of taste mostly.
Taste would also guide you as to whether you like the declaration on the event consumer side better:
In case of a full delegate declaration:
Eventful eventSource = new Eventful();
eventSource.MyCustomEvent += new Eventful.SomethingHappenedEventHandler(OnSomethingHappenedEvent);
But if a generics EventHandler is used:
eventSource.MyCustomEvent += new EventHandler<TypedEventArg<MyObject>>(classWithEvent2_SomethingHappendedEvent);
In conclusion, by creating a simple generic type around EventArgs, I can save a few keystrokes and learn something while at it. Left as a future excercise : look at adding a constraint to the argument type such that the argument type is serializeable.
1788e4ff-4fde-4b42-8332-1d9c533f166b|0|.0