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