Wil*_*son 10 c# covariance contravariance variance
C#规范声明参数类型不能同时具有协变性和逆变性.
这在创建协变或逆变接口时很明显,您可以分别使用"out"或"in"来修饰类型参数.没有选项允许同时("outin").
这种限制只是一种语言特定的约束,还是存在更深层次,更基本的理由,这种理由会使你不希望你的类型既有协变性又有逆变性?
编辑:
我的理解是阵列实际上既是协变的又是逆变的.
public class Pet{}
public class Cat : Pet{}
public class Siamese : Cat{}
Cat[] cats = new Cat[10];
Pet[] pets = new Pet[10];
Siamese[] siameseCats = new Siamese[10];
//Cat array is covariant
pets = cats;
//Cat array is also contravariant since it accepts conversions from wider types
cats = siameseCats;
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 24
正如其他人所说,泛型类型在协变和逆变方面在逻辑上是不一致的.到目前为止,这里有一些很好的答案,但我还要补充两个.
首先,请阅读关于方差"有效性"主题的文章:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx
根据定义,如果类型是"协同有效",则它不能以逆变方式使用.如果它是"违反有效的"那么它就不能以协变的方式使用.东西是两个协变有效,contravariantly有效是不是在任何一个协变或逆变方式使用.也就是说,它是不变的.因此,有是协变和逆变的工会:他们的结合是不变的.
其次,让我们假设您已经实现了您的愿望,并且有一种类型注释按照我认为您想要的方式工作:
interface IBurger<in and out T> {}
Run Code Online (Sandbox Code Playgroud)
假设你有一个IBurger<string>.因为它是协变的,可以转换为IBurger<object>.因为它是逆变的,IBurger<Exception>即使"字符串"和"例外"没有任何共同之处,它又可以转换为.基本上"进出"是指IBurger<T1>可转换为任何类型的IBurger<T2>任何两个引用类型T1和T2.这有用吗?你会用这样的功能做什么?假设你有一个IBurger<Exception>,但对象实际上是一个IBurger<string>.你能做些什么,它既利用了type参数是Exception的事实,又允许那个类型参数成为一个完整的谎言,因为"真正的"类型参数是一个完全不相关的类型?
要回答您的后续问题:涉及数组的隐式引用类型转换是协变的 ; 它们不是逆变的.你能解释为什么你错误地认为它们是逆变的吗?
协方差和逆变是相互排斥的.你的问题就像询问集合A是否可以是集合B的超集和集合B的子集.为了使集合A既是集合B的子集又是超集集合,集合A必须等于集合B,所以那么你只会问集合A是否等于集合B.
换句话说,在同一个论点上要求协方差和逆变就像要求没有方差(不变性),这是默认的.因此,不需要关键字来指定它.
对于您从未输入的类型,协方差是可能的(例如,成员函数可以将其用作返回类型或out参数,但从不作为输入参数使用).对于您从不输出的类型,可能存在逆变化(例如,作为输入参数,但从不作为返回类型或out参数).
如果您创建了一个covariant和contravariant类型参数,则无法输入它而无法输出它 - 您根本无法使用它.