It makes a lot of sense if you think in terms of Animals and Dogs.
Let's make up some concrete implementations first:
class AnimalHandler: IHandler<Animal> {
public void SetNext(IHandler<Animal> next) {
// animal handlers can handle cats :)
next.Handle(new Cat());
}
// ...
}
class DogHandler: IHandler<Dog> { ... }
Since the type parameter of IHandler is contravariant, a IHandler<Animal> is a kind of IHandler<Dog>:
IHandler<Animal> someAnimalHandler = new AnimalHandler();
IHandler<Dog> dogHandler = someAnimalHandler;
Suppose that your SetNext method is allowed to be declared in IHandler, then I can call SetNext with another IHandler<Dog> on this dogHandler, since that is exactly the type that dogHandler.SetNext accepts.
IHandler<Dog> anotherDogHandler = new DogHandler();
dogHandler.SetNext(anotherDogHandler);
But that shouldn't be possible! After all, dogHandler actually stores an instance of AnimalHandler, whose SetNext method accepts IHandler<Animal>, and a IHandler<Dog> is not necessarily a IHandler<Animal>, is it? Imagine what would happen if the implementation of AnimalHandler.SetNext actually runs - keep in mind that the next parameter is a DogHandler - we would be asking a dog handler to handle a cat!
Therefore, it is invalid to declare SetNext with a contravariant TEvent.
This is specified more precisely here. It is said that the type IHandler<TEvent> is input-unsafe, and so is prohibited as a parameter.
TEvent would have to be invariant for both of your interface methods to compile.