C#通用调用

时间:2019-09-28 18:15:00

标签: c# generics

我正在尝试实现诸如EventBus之类的东西,我的类是:

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
    }
}

以及预期的用法:

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

显然,EventBus无法正常工作,因为在调用Handle之前,我必须存储类型或强制转换事件/事件处理程序

有任何线索吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

您遇到的问题是此行key if (keyArray[i].Key.Equal(key)) //Use ".Equals()" instead of "==" { keyArray[i] = new KeyValueGeneric<T>(key, value); matchFound = true; } 是类型var eventType = event_.GetType();,其中不包含名为var的方法

所以您要做的是像{p1一样将Type的{​​{1}}更改为

Handle

提琴https://dotnetfiddle.net/UrnCv5

答案 1 :(得分:1)

在可能相当迅速地发送事件的环境中使用dynamic可能会涉及过多的开销。

代替查找处理程序对象,而是查找处理程序委托。

进一步的解释在下面的代码中。

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);
    }
}