- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
此代码之所以有效,是因为 Enumerator
无法修改集合:
var roList = new List<string>() { "One", "Two", "Three" };
IEnumerable<object> objEnum = roList;
如果我们尝试对 List<object>
做同样的事情, 而不是 IEnumerable<object>
,我们会得到一个编译器错误,告诉我们不能隐式转换类型 List<string>
至 List<object>
.好吧,这是有道理的,在我看来,这是微软的一个很好的决定,作为从数组中吸取的教训。
但是,我不明白的是,为什么这个强硬规则适用于 ReadOnlyCollection
之类的东西? ?我们将无法修改 ReadOnlyCollection
中的元素,那么导致 Microsoft 阻止我们对只读内容使用协变的安全问题是什么?是否有一种可能的方法来修改 Microsoft 试图解释的那种类型的集合,例如通过指针?
最佳答案
变体和逆变仅适用于接口(interface)和委托(delegate),不适用于类。
但是,您可以这样做(使用 .NET 4.5):
ReadOnlyCollection<string> roList = ...
IReadOnlyCollection<object> objects = roList;
(因为 IReadOnlyCollection<T>
是协变的)
为了回答关于为什么类中不允许差异的问题,这里是 Jon Skeet 在他的 C# in Depth 中的解释。书(第二版,§13.3.5,第 394 页)。
NO VARIANCE FOR TYPE PARAMETERS IN CLASSES
Only interfaces and delegates can have variant type parameters. Even if you have a class that only uses the type parameter for input (or only uses it for output), you can’t specify the
in
orout
modifiers. For exampleComparer<T>
, the common implementation ofIComparer<T>
, is invariant — there’s no conversion fromComparer<IShape>
toComparer<Circle>
.Aside from any implementation difficulties that this might’ve incurred, I’d say it makes a certain amount of sense conceptually. Interfaces represent a way of looking at an object from a particular perspective, whereas classes are more rooted in the object’s actual type. This argument is weakened somewhat by inheritance letting you treat an object as an instance of any of the classes in it s inheritance hierarchy, admittedly. Either way, the CLR doesn’t allow it.
关于c# - 为什么 ReadOnlyCollection 不允许协方差?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25575873/
在我的设置中,我试图有一个界面 Table继承自 Map (因为它主要用作 map 的包装器)。两个类继承自 Table - 本地和全局。全局的将有一个可变的映射,而本地的将有一个只有本地条目的映射。
Rust Nomicon 有 an entire section on variance除了关于 Box 的这一小节,我或多或少地理解了这一点和 Vec在 T 上(共同)变体. Box and Vec
我是一名优秀的程序员,十分优秀!