EventDistributor

In many projects some kind of event handling may be required and this EventDistributor is a good help to distribute events based on inheritance. However, this approach is slower than the built in event handling system. using System; using System.Collections.Generic; namespace VariousDevelopment.Utils { /// <summary> /// EventDistributor distributes events of type TRootEvent using inheritance. /// </summary> /// <typeparam name="TRootEvent">The root event type</typeparam> public class EventDistributor<TRootEvent> { private static Dictionary<Type, List<Type>> allInheritanceTypes = new Dictionary<Type, List<Type>>(); private Dictionary<Type, List<object>> eventHandlers = new Dictionary<Type, List<object>>(); /// <summary> /// Register an eventHandler on type TEvent. /// </summary> /// <typeparam name="TEvent">The event type to register on</typeparam> /// <param name="eventHandler">The event handler to handle event of type TEvent</param> public void RegisterEventHandler<TEvent>(Action<TEvent> eventHandler) where TEvent : TRootEvent { Type type = typeof(TEvent); if (!eventHandlers.ContainsKey(type)) { eventHandlers.Add(type, new List<object>()); } eventHandlers[type].Add(eventHandler); } /// <summary> /// Unregister an eventHandler on type TEvent. /// </summary> /// <typeparam name="TEvent">The event type to register on</typeparam> /// <param name="eventHandler">The event handler to handle event of type TEvent</param> public void UnregisterEventHandler<TEvent>(Action<TEvent> eventHandler) where TEvent : TRootEvent { Type type = typeof(TEvent); if (eventHandlers.ContainsKey(type)) { eventHandlers[type].Remove(eventHandler); } } /// <summary> /// Distribute event e on all eventHandlers registered on type TEvent. /// </summary> /// <typeparam name="TEvent">The event type to distribute</typeparam> /// <param name="e"></param> public void DistributeEvent<TEvent>(TEvent e) where TEvent : TRootEvent { foreach (Type type in GetInheritanceTypes(typeof(TEvent))) { DistributeEvent(type, e); } } private void DistributeEvent<TEvent>(Type type, TEvent e) where TEvent : TRootEvent { if (!eventHandlers.ContainsKey(type)) { return; } foreach (object obj in eventHandlers[type]) { Action<TEvent> eventHandler = (Action<TEvent>)obj; eventHandler(e); } } private static List<Type> GetInheritanceTypes(Type type) { if (allInheritanceTypes.ContainsKey(type)) { return allInheritanceTypes[type]; } List<Type> inheritanceTypes = new List<Type>(); Type currentType = type; while (currentType != typeof(object) && typeof(TRootEvent).IsAssignableFrom(type)) { inheritanceTypes.Add(currentType); currentType = currentType.BaseType; } foreach (Type interfaceType in type.GetInterfaces()) { if (typeof(TRootEvent).IsAssignableFrom(interfaceType)) { inheritanceTypes.Add(interfaceType); } } allInheritanceTypes.Add(type, inheritanceTypes); return inheritanceTypes; } } } This event system has the advantage of classifying events, e.g. you can have a StepForward event that inherits Movement and PropertyChange event. When a StepForward event is triggered, then all instances that listens on StepForward, Movement or PropertyChange events will be triggered. This version cannot listen on a specific instance, but that will be added in future.
Usage: public interface Event {} public class PropertyChangeEvent : Event {} public class MoveEvent : PropertyChangeEvent { int Steps { get; private set; } public MoveEvent(int steps) { Steps = steps; } } private int main() { EventDistributor<Event> eventDistributor = new EventDistributor<Event>(); eventDistributor.RegisterEventHandler<Event>(ListenOnEvent); eventDistributor.RegisterEventHandler<PropertyChangeEvent>(ListenOnPropertyChangeEvent); eventDistributor.RegisterEventHandler<MoveEvent>(ListenOnMoveEvent); eventDistributor.DistributeEvent(new PropertyChangeEvent()); eventDistributor.DistributeEvent(new MoveEvent(3)); } private void ListenOnEvent(Event event) { // Do stuff with Event } private void ListenOnPropertyChangeEvent(PropertyChangeEvent propertyChangeEvent) { // Do stuff with PropertyChangeEvent } private void ListenOnMoveEvent(MoveEvent moveEvent) { // Do stuff with MoveEvent } And that is how it can be used