I am trying to implement the Domain Event pattern in C# using Simple Injector.
I have simplified my code to be in one file that can be ran as a console app and have excl
Here is a faster version using cached delegates. No dynamic and no reflection after the first call. Uses IServiceProvider
from the default Microsoft DI but that can be easily changed. Expression trees can be used too, but they take more memory:
public class EventDispatcherService : IEventDispatcher
{
private static readonly ConcurrentDictionary>> HandlersCache
= new ConcurrentDictionary>>();
private static readonly Type HandlerType = typeof(IEventHandler<>);
private static readonly MethodInfo MakeDelegateMethod = typeof(EventDispatcherService)
.GetMethod(nameof(MakeDelegate), BindingFlags.Static | BindingFlags.NonPublic);
private static readonly Type OpenGenericFuncType = typeof(Func<,>);
private static readonly Type TaskType = typeof(Task);
private readonly IServiceProvider serviceProvider;
public EventDispatcherService(IServiceProvider serviceProvider)
=> this.serviceProvider = serviceProvider;
public async Task Dispatch(IDomainEvent domainEvent)
{
var eventHandlers = HandlersCache.GetOrAdd(domainEvent.GetType(), eventType =>
{
var eventHandlerType = HandlerType.MakeGenericType(eventType);
var makeDelegate = MakeDelegateMethod.MakeGenericMethod(eventType);
var funcType = OpenGenericFuncType.MakeGenericType(eventType, TaskType);
return this.serviceProvider
.GetServices(eventHandlerType)
.Select(handler => handler
.GetType()
.GetMethod("Handle")
.CreateDelegate(funcType, handler))
.Select(handlerDelegateConcrete => (Func
And this is the event handler interface:
public interface IEventHandler
where TEvent : IDomainEvent
{
Task Handle(TEvent domainEvent);
}