即使将T限制为从事件扩展,也无法从Action <t>转换为Action <event>?

时间:2019-01-26 04:22:08

标签: c# generics

我在下面发布了代码,我无法弄清楚为什么这不可能。我收到一个编译器错误:无法从System.Action转换为System.Action。

实现这样的东西的正确方法是什么?

我来自Java背景,我正在尝试使用通配符泛型来完成通常可以做的事情。但是我不明白为什么当T被限制为扩展Event时会出现此错误。

我省略了确保列表实际退出的代码。

    public class EventBus : ScriptableObject {

        public Event[] events;

        private Dictionary<Type, List<Action<Event>>> listeners = new Dictionary<Type, List<Action<Event>>>();

        public void Register<T>(Action<T> function) where T : Event {
            listeners[typeof(T)].Add(function);
        }

    }

    // The event class
    public abstract class Event : ScriptableObject {
        public abstract void Raise();
    }

更新

基本,我正在尝试执行以下操作:

eventBus.register<CutomEvent>(MyFunction); 

其中

public void MyFunction(CustomEvent event);

这样,我可以使用通用参数指定要监听的事件。字典仅包含要侦听特定事件类型的每个函数的列表

更新: 这就是我在Java中拥有的东西

public class EventBus {

    public Map<Class<?>, List<SomeInterface<?>>> listeners = new HashMap<>();

    public<T extends Event> void register(SomeInterface<T> func, Class<T> clazz) {
        listeners.get(clazz).add(func);
    }

    public interface SomeInterface<T extends Event> {
        void process(T event);
    }

    public static void main(String[] args) {

        new EventBus().register(event -> {
            // Do something with my event
            event.someFunc();
        }, MyEvent.class);

    }

    private static class MyEvent extends Event {
        public void someFunc(){}
    }

}

1 个答案:

答案 0 :(得分:2)

即使Action<T>也不能将Action<Event>强制转换为T : Event,但是可以将任何Action<T>强制转换为Delegate,然后冒着以下风险:运行时错误,将Delegate转换回Action<T>。但是,由于字典的键是typeof(T),因此可以避免发生运行时错误的风险。

尝试以下代码:

public class EventBus : ScriptableObject
{
    public Event[] events;

    private Dictionary<Type, List<Delegate>> listeners
        = new Dictionary<Type, List<Delegate>>();

    public void Register<T>(Action<T> function) where T : Event
    {
        listeners[typeof(T)].Add(function);
    }

    public Action<T>[] Retrieve<T>() where T : Event
    {
        return listeners[typeof(T)].Cast<Action<T>>().ToArray();
    }
}