1

I apologize for the confusing title, I'm not quite sure how to word my issue concisely. Here, I have a class structure that does not compile.

class MyEvent
{ }

class EventA : MyEvent
{ }

class EventB : MyEvent
{ }

class MyEventHandler<T>
    where T : MyEvent
{ }

class EventAHandler : MyEventHandler<EventA>
{ }

class EventBHandler : MyEventHandler<EventB>
{ }

/*** Tests ***/

abstract class MyEventHandlerTesterBaseClass<SomeEventHandler>
    where SomeEventHandler : MyEventHandler<MyEvent>
{
    // Plan to set up handler for the concrete test classes below.
    protected SomeEventHandler handler;  
}

class EventAHandlerTests : MyEventHandlerTesterBaseClass<EventAHandler>
{ }

class EventBHandlerTests : MyEventHandlerTesterBaseClass<EventBHandler>
{ }

It results in the following error on my class EventAHandlerTests definition:

The type 'EventAHandler' must be convertible to 'MyEventHandler<MyEvent>' in order to use it as parameter 'SomeEventHandler' in the generic class 'MyEventHandlerTesterBaseClass<SomeEventHandler>'

and similarly for EventBHandlerTests.

My understanding is that EventAHandler should be convertible to MyEventHandler<MyEvent> because EventAHandler inherits MyEventHandler<EventA>, and thus EventA should dynamically bind to MyEvent.

Am I doing something wrong? Or is this impossible?

  • Does this answer your question? [Covariance and contravariance real world example](https://stackoverflow.com/questions/2662369/covariance-and-contravariance-real-world-example) – Charlieface May 05 '21 at 23:12

1 Answers1

2

The problem is that a generic class of type T cannot be cast to another generic class of type U : T.

For example:

class Foo { }
class Bar : Foo { }

void test()
{
  List<Bar> bars;
  List<Foo> foos = bars; //does not work!!!
}

In your case, MyEventHandlerTesterBaseClass expects the generic type to be of MyEventHandler<MyEvent> but EventAHandler is of type MyEventHandler<EventA> and therefor does not work. This can be circumvented by using two generics like so:

abstract class MyEventHandlerTesterBaseClass<THandler, TEvent>
    where THandler : MyEventHandler<TEvent>
    where TEvent : MyEvent
Dharman
  • 30,962
  • 25
  • 85
  • 135
Jack T. Spades
  • 986
  • 6
  • 9