C# 支持单个类型参数的协方差和逆变

C# 支持单个类型参数的协方差和逆变,c#,generics,interface,covariance,contravariance,C#,Generics,Interface,Covariance,Contravariance,可能重复: 您可以使用out关键字将泛型类型参数声明为协变: interface ICovariant<out R> interface IContravariant<in R> 对于不同的类型参数,您还可以同时支持这两种类型: interface IVariant<out R, in A> 接口变量 那么,为什么不能为单个类型参数同时支持这两种类型呢 那么,为什么不能为单个类型参数同时支持这两种类型呢 请记住,如果类型参数是输出安全的,则接口只能在

可能重复:

您可以使用
out
关键字将泛型类型参数声明为协变:

interface ICovariant<out R>
interface IContravariant<in R>
对于不同的类型参数,您还可以同时支持这两种类型:

interface IVariant<out R, in A>
接口变量
那么,为什么不能为单个类型参数同时支持这两种类型呢

那么,为什么不能为单个类型参数同时支持这两种类型呢

请记住,如果类型参数是输出安全的,则接口只能在类型参数中是协变的;如果类型参数是输入安全的,则接口只能在类型参数中是逆变的

语法
out T
表示
T
是协变类型参数

T中的语法
表示
T
是一个逆变类型参数

由于
T
是一个协变类型参数,根据定义,它是不安全的输入

由于
T
是一个逆变型参数,根据定义,它是不安全的输出

因此,
T
输入不安全,输出不安全

因此,
T
在输入位置被禁止,而
T
在输出位置被禁止

因此,
T
不能出现在接口指定的任何方法的输入位置或任何输出位置

因此,
T
根本不能在接口上使用,并且作为类型参数毫无意义。因此,语言设计者甚至禁止您在界面上包含这样一个无用的类型,该类型被标记为协变和逆变,以避免出现丑陋的界面

interface IFoo<in and out T> { }
Foo<T> : IFoo<T> { }
接口IFoo{}
Foo:IFoo{}
然后:

IFoo<Cat> cat = (IFoo<Animal>)new Foo<Dog>();
ifoocat=(IFoo)new Foo();

(如果您需要阅读输入安全和输出安全,请参阅语言规范的13.1.3.1。)

它不起作用。考虑这个(如果<代码>在< < /代码>中):

这将不起作用,因为这意味着您可以传入一个
new Dog()
实例,在该实例中,原始接口预期会出现一只猫

同样,在out(输出)位置上也会出现相反的情况,因为这将允许:

Puma DoIt(...)

这将是无效的,因为原始界面可以传回任何猫科动物,不一定是美洲狮。

wow这是一个很难理解的答案:)@john:谢谢,我再试了一次。让我知道你的想法?那就行了。虽然我的大脑现在开始有点痛了。实际上,在某些情况下,接口包含一个类型参数可能是有用的,它实际上不参与任何方法或属性。更大的问题是,如果对于从对象派生的任何T和U,Foo是Foo的有效替换,Foo是Foo的有效替换,那么Foo是Foo的有效替换。因为协变和逆变只适用于对象的导数,所以说一个接口是协变的,而T中的逆变将使T变得毫无意义。对不起,在我看到@Jason已经回答之前,我正在计算我的答案。不要道歉:-)对于同一件事有不同的方式总是很好的。@James Michael Hare:哈!我改进了我的答案,加入了一个微不足道的猫/狗的例子,而没有看到你的!这太有趣了@Jason!在这里,它似乎是同一个波长!詹姆斯,你今天似乎对变化感兴趣。你可能想看看我写的关于我们是如何设计这个功能的大量文章和视频。它们在这里:,从底部开始。
... DoIt(Animal item)
Puma DoIt(...)