这是因为如果您使用 'out' 参数修饰符进行协变,编译器可能会认为需要不安全的类型转换。
看到这个场景。假设有一个方法 f 期望 NotOK 作为输入:
interface NotOK<out T>
{
bool TryDequeue(out T t);
}
void f( NotOK<Animal> x)
{
bool b ;
Animal animal_in_f;
b = x.TryDequeue(animal_in_f);
}
看看如果我有两个接口会发生什么:
NotOK<Animal> objA;
NotOK<Dog> objD;
使用 objA 作为 f 的输入,没问题。
f(objA);
// objA should have a method of signature bool TryDequeue(out Animal t)
// inside method f, it calls x.TryDequeue(animal_in_f);
// where animal_in_f is Animal, type match
但如果允许协方差,则允许传递 objD
f(objD);
// objD should have a method of signature bool TryDequeue(out Dog t)
// inside method f, it calls x.TryDequeue(animal_in_f);
// where animal_in_f is Animal
// but this time x.TryDequeue is expecting a Dog!!
// It is unsafe to cast animal_in_f to Dog
所以你明白为什么不允许在协方差中使用 out 了。
我认为从概念上讲它应该可以工作,因为通过使用 out 参数修饰符,我们只希望将传递的变量作为输出。如果编译器有一个特殊的规则,它就会起作用,这样当它遇到上述情况时,它应该认为强制转换是安全的并且不会产生错误。
但是我认为 C# 设计师权衡了利弊,最终决定保持一致的类型检查规则,这通常是不允许的向下转换。
在我看来,最好添加该特殊规则,因为现在它限制了使用,说它不能有一个方法返回两个需要使用 out 参数修饰符的 T 类型对象。