Creating an event handler that handles several types of events

I looked over the old code today and found an event handler that looked like this:

public void HandleEvent(EventClassA eventObj) { if(eventObj is EventSubClassA) { HandleEventSubClassA(eventObj as EventSubClassA); } else if(eventObj is EventSubClassB) { HandleEventSubClassB(eventObj as EventSubClassB); } else if(eventObj.GetType() == typeof(EventSubClassC)) { HandleEventSubClassC(eventObj as EventSubClassC); } else if(eventObj is EventSubClassD) { HandleEventSubClassD(eventObj as EventSubClassD); } } 

I thought it was disgusting. So I reorganized it like this:

 delegate void EventHandler(dynamic eventObj); private static readonly Dictionary<Type, EventHandler> EVENT_MAP = new Dictionary<Type, EventHandler>() { { typeof(EventSubClassA), HandleEventSubClassA }, { typeof(EventSubClassB), HandleEventSubClassB }, { typeof(EventSubClassC), HandleEventSubClassC }, { typeof(EventSubClassD), HandleEventSubClassD } }; public void HandleEvent(EventClassA eventObj) { EVENT_MAP[eventObj.GetType()](eventObj); } private void HandleEventSubClassA(dynamic evt) { var eventObj = evt as EventSubClassA; } 

I had a colleague looking at the code, and I had concerns about how this solution works compared to the previous solution. I hardly believe that the previous solution is the best solution for this case, so I switched to StackOverflow.

Is there a better way to build this type of class? Is there a pattern that I don't know about that is designed for this?

+4
source share
2 answers

You can use generics to make an existing solution safer:

 private static Dictionary<Type, Delegate> handlers; static HandlerClass() { handlers = new Dictionary<Type, Delegate>(); AddHandler<EventSubClassA>(HandleEventSubClassA); AddHandler<EventSubClassB>(HandleEventSubClassB); ... } public static void AddHandler<T>(Action<T> handler) where T : EventClassA { handlers[typeof(T)] = handler; } public void HandleEvent(EventClassA @event) { Delegate handler; if(handlers.TryGetValue(@event.GetType(), out handler)) { handler.DynamicInvoke(@event); } } 

Alternatively, if you can change the classes in the event hierarchy, you can implement the visitor template:

 public interface IHandlers { void HandleSubClassA(EventSubClassA a); void HandleSubClassB(EventSubClassB b); ... } public abstract class EventClassA { public abstract void Visit(IHandlers handlers); } public class EventSubClassA : EventClassA { public override void Visit(IHandlers handlers) { handlers.HandleSubClassA(this); } } 
+3
source

It seems to me that I'm missing something. Isn't the best way to write overloads for each type of event?

+1
source

All Articles