为什么不能将逆变接口作为接口方法的参数?
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.
我认为这应该是有效的,因为 IHandler
在 TEvent
中是协变的。我错过了什么?
如果您根据 Animal
s 和 Dog
s 来思考,这很有意义。
我们先来做一些具体的实现:
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
两个接口方法都必须是不变的才能编译。
我正在尝试使用接口设置 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.
我认为这应该是有效的,因为 IHandler
在 TEvent
中是协变的。我错过了什么?
如果您根据 Animal
s 和 Dog
s 来思考,这很有意义。
我们先来做一些具体的实现:
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
两个接口方法都必须是不变的才能编译。