C#推断带有约束的Generic类型

时间:2013-12-23 16:52:56

标签: c# events generics types type-inference

我试图通过以下方式注册从基类派生的泛型,但得到错误:

  

无法将MyCallback<T>表达式转换为MyCallback<Event>

类型

我希望限制会使这成为可能,但我错过了什么?

public class Event
{ };

public delegate void MyCallback<T>(T arg1) where T : Event;

static class EventDispatcher
{

    public static Dictionary<string, MyCallback<Event>> eventTable = new Dictionary<string, MyCallback<Event>>();

    static void RegisterCallback<T>(MyCallback<T> callback) where T : Event
    {
        eventTable.Add("test", callback);
    }
}

2 个答案:

答案 0 :(得分:0)

您需要将type参数作为EventDispatcher类的一部分:

public class EventDispatcher<T> : where T : Event {
  public Dictionary<string, MyCallback<T>> eventTable = new Dictionary<string, MyCallback<T>>();

  void RegisterCallback(MyCallback<T> callback) {
    eventTable.Add("test", callback);
  }
}

这是因为MyCallback<Event>中声明的eventTable在编写时不会被编译为RegisteredCallback中声明的相同类型。

答案 1 :(得分:0)

当你有一个MyCallback<Event>时,你说你有一个可以采用任何类型的事件的方法。它可以接受EventOneEventTwoSomeOtherEvent

假设我调用RegisterCallback并传入指向具有此签名的方法的委托:

public static void Foo(SomeOtherEvent arg)

如果您的代码可行,并且我可以将其分配给MyCallback<Event>,那么我可以在调用它时将EventOne实例传递给该方法。这显然是一个问题。

有一个术语;你希望MyCallback协变的关于它的泛型参数。事实上,它是逆变。如果我有一个方法可以接受任何类型的事件,我可以清楚地传入SomeEventSomeOtherEvent,这意味着我可以指定MyCallback<Event>MyCallback<SomeOtherEvent>,而不是相反。

如果你想告诉编译器,“我知道这个方法实际上不能用任何类型的事件调用,但我希望你允许这个检查,只有在给定的参数不合适时才会在运行时失败类型。”然后你可以这样做,假设你确实有办法确保用适当的参数调用每个回调。你不能只是做演员;你需要将方法包装在一个执行强制转换的新方法中:

eventTable.Add("test", e => callback((T)e));