为什么不能将逆变接口作为接口方法的参数?

Why can't I take a contravariant interface as a parameter to a method on the interface?

我正在尝试使用接口设置 CoR,其中链中的处理程序可以是使用逆变的派生较少的事件类型。我创建这个界面来做它。

public interface IHandler<in TEvent>
{
    void SetNext(IHandler<TEvent> next);
    void Handle(TEvent event);
}

它因编译器错误而失败

CS1961 Invalid variance: The type parameter 'TEvent' must be covariantly valid on 'IHandler.SetNext(IHandler)'. 'TEvent' is contravariant.

我认为这应该是有效的,因为 IHandlerTEvent 中是协变的。我错过了什么?

如果您根据 Animals 和 Dogs 来思考,这很有意义。

我们先来做一些具体的实现:

class AnimalHandler: IHandler<Animal> { 
    public void SetNext(IHandler<Animal> next) {
        // animal handlers can handle cats :)
        next.Handle(new Cat());
    }

    // ...
}

class DogHandler: IHandler<Dog> { ... }

由于 IHandler 的类型参数是逆变的,所以 IHandler<Animal> 是一种 IHandler<Dog>:

IHandler<Animal> someAnimalHandler = new AnimalHandler();
IHandler<Dog> dogHandler = someAnimalHandler;

假设你的SetNext方法允许在IHandler中声明,那么我可以在这个dogHandler上用另一个IHandler<Dog>调用SetNext,因为这正是 dogHandler.SetNext 接受的类型。

IHandler<Dog> anotherDogHandler = new DogHandler();
dogHandler.SetNext(anotherDogHandler);

但这不可能!毕竟,dogHandler实际上存储了一个AnimalHandler的实例,其SetNext方法接受IHandler<Animal>,而IHandler<Dog>不一定是IHandler<Animal>,是吗?想象一下如果 AnimalHandler.SetNext 的实现实际运行会发生什么 - 请记住 next 参数是一个 DogHandler - 我们会要求狗处理程序处理一只猫!

因此,用逆变TEvent声明SetNext是无效的。

这更准确地指定了 here。据说类型 IHandler<TEvent>input-unsafe,因此被禁止作为参数。

TEvent 两个接口方法都必须是不变的才能编译。