fj123x
fj123x

Reputation: 7492

C# generic call

I'm trying to implement something like an EventBus, my classes are:

public interface IEventHandler<in T>
{
    void Handle(T event_);
}
public class SomeEventHandler: IEventHandler<SomeEvent>
{
    public void Handle(SomeEvent event_)
    {
        Console.WriteLine(event_.SomeData);
    }
}

public class SomeEvent
{
    private readonly string _someData;

    public string SomeData { get => _someData; }

    public SomeEvent(string someData)
    {
        _someData = someData;
    }
}
public class EventBus
{
    private readonly Dictionary<Type, object> _handlers = new Dictionary<Type, object>(); // probably the object should be something like IEventHandler<?>

    public void Register<T>(IEventHandler<T> eventHandler)
    {
        _handlers[typeof(T)] = eventHandler;
    }

    public void Handle(object event_) // I want to keep this Handle interface as (object event_) (without any <T>)
    {
        var eventType = event_.GetType();
        var eventHandler = _handlers[eventType];
        eventHandler.Handle(event_); // this will not work
    }
}

And the expected usage:

var eventBus = new EventBus();
eventBus.Register(new SomeEventHandler());
eventBus.Handle(new SomeEvent("some data"));

Obviously the EventBus isn't working because I have to store the type or cast the event / event handler before calling the Handle

Any clue?

Thanks!

Upvotes: 0

Views: 94

Answers (2)

madreflection
madreflection

Reputation: 4947

Using dynamic in an environment where you could be pumping events fairly rapidly will likely involve too much overhead.

Instead of keeping a lookup of handler objects, keep a lookup of handler delegates.

Further explanation is within the code that follows.

public class EventBus
{
    // Change the type of values to Action<object>
    private readonly Dictionary<Type, Action<object>> _handlers = new Dictionary<Type, Action<object>>();

    public void Register<T>(IEventHandler<T> eventHandler)
    {
        // When you store the lookup, create the handler.
        _handlers[typeof(T)] = CreateHandler(eventHandler);
    }

    private Action<object> CreateHandler<T>(IEventHandler<T> eventHandler)
    {
        // The lambda that's created here is an Action<object> and the cast assumes that
        // someData is of the correct type.
        return someData => eventHandler.Handle((T)someData);
    }

    public void Handle(object @event)
    {
        var eventType = @event.GetType();
        var eventHandler = _handlers[eventType];

        // The dictionary gives back an Action<object> that you can call directly.
        eventHandler(@event);
    }
}

Upvotes: 1

TiGreX
TiGreX

Reputation: 1816

the problem you have is that this line var eventType = event_.GetType(); var is the type Type which does not contains a method called Handle

so what you have to do is change the public void Handle(object event_) for dynamic like

public void Handle(dynamic event_) 
{
    var eventType = event_.GetType();
    var eventHandler = _handlers[eventType];
    eventHandler.Handle(event_); // this will work
}

fiddle https://dotnetfiddle.net/UrnCv5

Upvotes: 2

Related Questions