为什么在.NET 4.5中List<T>实现了IReadOnlyList<T>接口?

50
为什么在.NET 4.5中,List 实现了 IReadOnlyList?
List 不是只读的...

BCL团队成员的回答:https://stackoverflow.com/a/35940240 - undefined
7个回答

54
因为List<T>实现了IReadOnlyList<T>的所有必要方法/属性等(甚至更多)。接口是一种合同,表示“我至少可以做这些事情。”

IReadOnlyList<T>的文档说它表示一个只读元素集合。

没错。在该接口中没有变异器方法。这就是只读的含义,对吧? IReadOnlyList<T>以“典型”的(合同)方式使用,而不是作为marker

39
接口并不能保证列表不会被修改,它只是意味着你无法通过接口进行修改。 - Brandon
17
按照这个逻辑,IList<T> 不应该实现 IReadOnlyList<T> 吗?我认为这很傻。 - James Newton-King
10
应该是这样的!但由于这将是一项破坏性的更改,所以目前还不能实现。请阅读我之前提供的链接。 - Brandon
5
“是一个”(is a)的解释对于开始面向对象编程很有用,来描述类型和子类型之间的关系。然而,它并不适用于更深入的程度。 - Tormod
9
“这就是只读的意思,对吧?”-- 嗯,不是的。虽然我不是律师,但我可以确定地说,“仅”字出现在合同中的含义与“至少”是非常不同的。IListIsReadOnly 属性正确地应用了这个术语,当读取和写入均可行时,该属性值为 false。这个接口应该被命名为类似于 IIndexable 的名称。 - nmclean
显示剩余6条评论

34

接口只描述将要实现的功能。它不描述将不会实现的功能。因此,IReadOnlyList是一个不正确的接口名称,因为它不能指定写功能不会被编写。

这些方法/函数描述您可以读取列表的内容。接口应该为IReadableList而不是IReadOnlyList。


1
这绝对有值得一提的地方。 - Mark
14
我同意;这个名字中的“Only”一词令人不安。 - hypehuman

7
实现一个接口并不等同于“标记”它。List也实现了IEnumerable,但这并不意味着你只能枚举它。
他们添加了只读接口用于API创建,而不是让你将只读类型标记为一个接口。它允许我在参数中使用IReadOnlyCollection,当我只想知道集合中元素的数量而不枚举它时,或者使用IReadOnlyList,当我需要通过它们的索引引用集合中的元素时。这对每个人都很好--我可以明确地告诉我的调用者我需要什么,同时允许我的调用者使用任何集合类型,只要它满足我通过参数类型设置的最低标准。
因此,我认为更困难的问题是,为什么你不应该让List实现IReadOnlyList?

类似的“为什么不”问题在https://dev59.com/GGcs5IYBdhLWcg3wu2Yp上被问到。答案是“这样做会导致向后兼容性破坏。” 这让我感到难过。 - Tim Sparkles

6
实现接口并不意味着它是只读的。但由于它实现了接口,因此您现在可以将其传递给期望一个的方法。因此,看待它的方式是,它实现了只读列表接口...以及一些写入方法。

5
接口 IReadOnlyListIReadOnlyCollection 有点令人困惑,因为它们并不意味着集合是只读的,而是支持只读访问。请参阅MSDN文档(向下滚动到“备注”部分)。

列表元素的内容不能保证是只读的。

更好的名字应该是 IReadable,请参阅 为什么泛型 ICollection 在 .NET 4.5 中没有实现 IReadOnlyCollection。此外,这意味着 IList 应该继承 IReadOnlyList,尽管由于向后兼容性而未继承,详见 为什么 IList<T> 没有继承自 IReadOnlyList<T>

1
IReadOnlyList是C++概念“引用不可变性”的替代品,在C#中找不到。C++的等效语句为:
void func(T const* t) {...} 或者,确切地说,一些人更喜欢:
void func(const T* t) {...}
它表明函数func不会改变其参数t所引用的对象(称为t的“引用对象”)。它对于任何其他代码是否改变t的引用对象甚至能否改变都没有说明。
因此,C#接口是编译器构造的替代品。为什么C#没有引用不可变性的概念是一个历史问题:我认为这是一个错误,但现在已经太晚了。我认为提供接口替代品很好。多年来我一直在使用与IReadOnlyList<>完全相同的接口,幸运的是有另一个名称,即IConstList<>。我可能会用IReadOnlyList<>替换我的IConstList<>使用。

0

难道不是这样吗?运行IReadOnlyList(Of T)调用实现该接口的对象的代码通常在同一执行线程上运行。这可以防止对象被自身修改,除非它在不同的执行线程上运行,但对于这种情况,我们有同步调用来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接