- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
C# 规范指出参数类型不能同时是协变和逆变的。
这在创建协变或逆变接口(interface)时很明显,您分别用“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;
最佳答案
正如其他人所说,泛型类型既是协变又是逆变在逻辑上是不一致的。到目前为止,这里有一些很好的答案,但让我再补充两个。
首先,阅读我关于方差“有效性”主题的文章:
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>
,即使“string”和“Exception”没有任何共同点。基本上“进出”意味着IBurger<T1>
可转换为任何类型IBurger<T2>
对于任意两个引用类型 T1 和 T2。 这有什么用?您会使用这样的功能做什么?假设你有一个 IBurger<Exception>
, 但对象实际上是一个 IBurger<string>
.你能用它做什么,两者都利用了类型参数是 Exception 的事实,并允许该类型参数是一个完整的谎言,因为“真实”类型参数是一个完全不相关的类型?
回答您的后续问题:涉及数组的隐式引用类型转换是协变;它们不是逆变的。你能解释为什么你错误地认为它们是逆变的吗?
关于c# - 同一类型参数的协变和逆变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4528186/
在我的设置中,我试图有一个界面 Table继承自 Map (因为它主要用作 map 的包装器)。两个类继承自 Table - 本地和全局。全局的将有一个可变的映射,而本地的将有一个只有本地条目的映射。
Rust Nomicon 有 an entire section on variance除了关于 Box 的这一小节,我或多或少地理解了这一点和 Vec在 T 上(共同)变体. Box and Vec
我是一名优秀的程序员,十分优秀!