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; 发布于 2010-12-25 01:42:01
正如其他人所说,泛型类型既是协变又是反变体,这在逻辑上是不一致的。到目前为止,这里有一些很好的答案,但让我再补充两个。
首先,阅读我关于方差“有效性”的文章:
http://blogs.msdn.com/b/ericlippert/archive/2009/12/03/exact-rules-for-variance-validity.aspx
根据定义,如果一个类型是“协变有效的”,那么它就不能以相反的方式使用。如果它是“相反有效的”,那么它就不能以协变的方式使用。既有效又相反有效的东西,无论是协变还是反变,都是不可用的。也就是说,它是不变的。所以,有协变和反变的结合:它们的结合是不变的。
第二,让我们假设您得到了您的愿望,并且有一个类型注释按照我认为您想要的方式工作:
interface IBurger<in and out T> {}假设您有一个IBurger<string>。因为它是协变的,所以可以转换为IBurger<object>。因为它是相反的,这反过来可转换为IBurger<Exception>,即使“字符串”和“异常”没有任何共同之处。基本上,“输入和输出”意味着IBurger<T1>对于任何两个引用类型T1和T2都可以转换为任何类型的IBurger<T2>。那有什么用?你会用这样的功能做什么?假设您有一个IBurger<Exception>,但是这个对象实际上是一个IBurger<string>。你能做些什么,既利用了类型参数是异常的事实,又允许类型参数完全是谎言,因为“真正的”类型参数是一个完全无关的类型?
要回答后续问题:涉及数组的隐式引用类型转换是协变的;它们不是反变体。你能解释一下你为什么不正确地相信它们是反差的吗?
发布于 2010-12-24 20:35:01
协方差和反方差是相互排斥的。你的问题就像问A既可以是集合B的超集,也可以是集合B的子集。为了使A既是集合B的子集又是集合B的超集,集合A必须等于集合B,所以您只需要问集A是否等于集合B。
换句话说,要求相同参数上的协方差和反方差就像根本不要求任何方差(不变性),这是默认的。因此,不需要关键字来指定它。
发布于 2010-12-24 20:36:43
对于从未输入的类型来说,协方差是可能的(例如,成员函数可以将其用作返回类型或out参数,但绝不用作输入参数)。对于从未输出的类型(例如,作为输入参数,但不作为返回类型或out参数),可以进行反方差。
如果你做了一个类型参数,不管是协变的还是反变的,你不能输入它,也不能输出它--你根本不能使用它。
https://stackoverflow.com/questions/4528186
复制相似问题