
Question:
I'm improving an existing messaging system for my project, which should accept a variable number of parameters. Right now generics are used to pass arguments to the system. A lot of code repeats itself, so the question is - is it possible to merge all the versions of the class that take different number of parameters into a one single class? The whole messaging system I take as a foundation for mine can be found here: <a href="http://www.unifycommunity.com/wiki/index.php?title=CSharpMessenger" rel="nofollow">CSharpMessenger</a>
Code excerpts:
public delegate void Callback();
public delegate void Callback<T>(T arg1);
public delegate void Callback<T, U>(T arg1, U arg2);
Version with no parameters:
static public class Messenger
{
private static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public void AddListener(string eventType, Callback handler)
{
if (!eventTable.ContainsKey(eventType))
{
eventTable.Add(eventType, null);
}
// Add the handler to the event.
eventTable[eventType] = (Callback)eventTable[eventType] + handler;
}
static public void Invoke(string eventType)
{
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback callback = (Callback) d;
if (callback != null)
{
callback();
}
}
}
}
Version with one parameter:
static public class Messenger<T>
{
private static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public void AddListener(string eventType, Callback<T> handler)
{
if (!eventTable.ContainsKey(eventType))
{
eventTable.Add(eventType, null);
}
// Add the handler to the event.
eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
}
static public void Invoke(string eventType, T arg1)
{
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback<T> callback = (Callback<T>) d;
if (callback != null)
{
callback(arg1);
}
}
}
}
Version with two parameters:
static public class Messenger<T, U>
{
private static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public void AddListener(string eventType, Callback<T, U> handler)
{
if (!eventTable.ContainsKey(eventType))
{
eventTable.Add(eventType, null);
}
// Add the handler to the event.
eventTable[eventType] = (Callback<T, U>)eventTable[eventType] + handler;
}
static public void Invoke(string eventType, T arg1, U arg2)
{
Delegate d;
if (eventTable.TryGetValue(eventType, out d))
{
Callback<T, U> callback = (Callback<T, U>) d;
if (callback != null)
{
callback(arg1, arg2);
}
}
}
}
As you can see most of the code repeats itself, Is it possible to create some general version of the same class, that will take a variable number of parameters and to avoid repeating the same code so many times?
Thanks.
Answer1:Callback parameters are normally passed in a subclass of EventArgs
. There's already a simple generic delegate that abstracts this: EventHandler<TEventArgs> where TEventArgs : EventArgs
. The variability in parameters can be added to subclasses of EventArgs
.
So, if you can restructure your code to use these classes, you can have just one version. Something like this:
public static class Messenger<TEventArgs> where TEventArgs : EventArgs {
private static Dictionary<string, EventHandler<TEventArgs>> eventTable =
new Dictionary<string, EventHandler<TEventArgs>>();
public static void AddListener(string eventType, EventHandler<TEventArgs> handler) {
if (eventTable.ContainsKey(eventType)) {
eventTable[eventType] = eventTable[eventType] + handler;
}
else {
eventTable.Add(eventType, handler);
}
}
public static void Invoke(string eventType, TEventArgs args) {
EventHandler<TEventArgs> d;
if (eventTable.TryGetValue(eventType, out d)) {
if (d != null) {
d(args);
}
}
}
}