I'm trying to register a generic that derives from a base class in the following way, but getting the error :
cannot convert
MyCallback<T>
expression to typeMyCallback<Event>
I was hoping the constraints would make this possible but am I missing something?
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);
}
}
You need to have the type parameter be part of the EventDispatcher
class:
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);
}
}
This is because the MyCallback<Event>
declared in eventTable
is not going to be compiled into the same type declared in RegisteredCallback
when written like your example.
When you have a MyCallback<Event>
you're saying that you have a method that can take any type of event. It can accept an EventOne
, or an EventTwo
, or a SomeOtherEvent
.
Let's say I call RegisterCallback
and pass in a delegate pointing to a method with this signature:
public static void Foo(SomeOtherEvent arg)
If your code would work, and I could assign that to a MyCallback<Event>
, then I could pass in an EventOne
instance to that method when calling it. That's obviously a problem.
There's a term for that; you're expecting MyCallback
to be covariant with respect to it's generic argument. In fact, it's contravariant . If I have a method that can accept any type of event, I can clearly pass in a SomeEvent
, or a SomeOtherEvent
, meaning I could assign a MyCallback<Event>
to a MyCallback<SomeOtherEvent>
, rather than the other way around.
If you want to tell the compiler that, "I know that this method cannot actually be called with any type of event, but I want you to allow this check and only fail at runtime if the given argument is not of the proper type." then you can do that, assuming you actually have a way of ensuring you call each callback with the proper arguments. You can't just do a cast either; you need to wrap the method in a new method that does the cast:
eventTable.Add("test", e => callback((T)e));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.