Introduction
This is an idea I had a few days back. While most of you out there will know how to create and use a generic EventHandler
and/or generic EventArg
s, it's that spicy little implicit cast operator that made me write this down for you.
I hope you find a little bit of useful information here.
Please leave me a note telling me if you already had the same idea that's shown here.
Background
We all have created EventHandlers
and have derived EventArgs
for lots of different reasons. I have used a generic implementation for years but was not really happy with the code, how it looked like... There were just too many brackets involved, especially when raising the event with a line like:
OnMyEvent(new GenericEventArgs<Dictionary<int, List<string>>>(myDic));
It would have been much nicer to raise the event just with:
OnMyEvent(myDic);
YES of course, I could just create an On
... method that takes the Dictionary
directly, but I didn't want that, as the protected virtual void OnEventName(EventArgs e)
method signature is a standard, and I don't like to break standards.
That's how I came to the idea. I will show you now.
Create a Generic EventHandler and EventArgs
Let's start with a generic EventHandler
and EventArgs
that will allow us to forward one single Data Item with the event. This is enough for most cases, as we can easily deliver a class or data holder of any kind with all the details that need to be delivered with the event.
(Comments are skipped here but in the downloadable file, everything is XML-commented of course):
public class ItemEventArgs<T> : EventArgs
{
public ItemEventArgs(T item)
{
Item = item;
}
public T Item { get; protected set; }
}
The EventHandler
for this is simple and straightforward, too:
public delegate void ItemEventHandler<T>(object sender, ItemEventArgs<T> e);
So now, we can declare any event that shall deliver one single item of data/information as follows (I take this from a real code where I use that delegate in a UDP communication class):
public event ItemEventHandler<DataPacket> PacketReceived;
and the protected
method to raise the event is completely standard, too:
protected virtual void OnPacketReceived(ItemEventArgs<DataPacket> e)
{
PacketReceived?.Invoke(this, e);
}
From my code, I could raise the event now as:
OnPacketReceived(new ItemEventArgs<DataPacket>(_packet));
It's this new ItemEventArgs<DataPacket>
that I didn't like too much, I preferred a call like:
OnPacketReceived(_packet);
without having to declare a On
... method that takes a packet directly. So I tried an implicit cast operator, wondering if this would work generic. And it does!
So, if you never did a cast operator like this, it will be new information for you, and I really had an "ahaaaaa!" effect when I found that out, and this is the reason for sharing it with you.
I put that cast operator in the ItemEventArgs<T>
class, and it did what I was really hoping for:
public static implicit operator ItemEventArgs<T>(T item)
{
return new ItemEventArgs<T>(item);
}
This little gem allowed me, from now on to call any of my On
... methods that work with the generic ItemEventargs
to be called directly with the object to deliver, and to skip the new ItemEventArgs<T>(...)
from now on.
The raising code in my UDP class (and many other classes) now really looks like:
OnPacketReceived(_packet);
without ever having to declare another On
... method that would break what is considered as "standard". Inheritors still find their common expected virtual method to override, but the callers can use it in a more readable way.
This generic implicit cast is not limited by the virtual On
... methods. ANY call, that expects ItemEventArgs<T>
can now be done directly without having to instantiate the <T>
class! You can do implicit generic casts like that for any class you make. Hope this gives you a new idea or two!
I discussed this with some colleagues here in the office and they all liked the idea because the code is more beautiful to read.
So if you didn't have the idea of a generic implicit cast operator so far, I hope you will take this for your own use.
For easier copying of the code, here it is, all in a single block:
using System;
namespace Mbi.Toolbox
{
public delegate void ItemEventHandler<T>(object sender, ItemEventArgs<T> e);
public class ItemEventArgs<T> : EventArgs
{
public ItemEventArgs(T item)
{
Item = item;
}
public T Item { get; protected set; }
public static implicit operator ItemEventArgs<T>(T item) => new ItemEventArgs<T>(item);
}
}
History
- 2013-01-11 Published
- 2015-09-22 Updated the event invoke to the new C# 6.0 syntax