为什么 List<T> 实现了 IReadOnlyList<T> 接口?

9

为什么 List<T> 实现了 IReadOnlyList<T>,即使 List<T> 并不是只读的?


1
我认为你混淆了派生和实现的基本原理。类从一个基类派生,但它们实现一个接口。牢记这一点可以解释这两个概念之间的区别。你并不是在说 IList<T> 是一个 IReadonLyList<T>,只是它可以被用作其中一个。 - itsme86
2
@itsme86,实际上使用他们所选择的设计是一个非常困难的设计决策。有人可能合理地期望IReadOnlyList永远不会改变,也就是说它是不可变的,而不是说它是对可变列表的引用,只是不能使用该引用进行突变(无需转换)。由于这种混淆,实际上对于List实现IReadOnlyList的决定存在一些阻力。 - Servy
好问题。在我看来,这个接口的命名不太好。它应该被称为类似 IAccessableByIndexList 的东西,虽然那也不是很好,但它不会让你误以为集合必须是只读的。 - Magnus
那似乎有些愚蠢。你可以有一个实现了接口IWritingUtencil的类Finger(只能在沙子、雪地或流血时使用?),但我不认为手指本质上是一种写作工具;只是它可以被用作其中之一。 - itsme86
2
我一直认为IReadOnlyList是个不太准确的名称。 IReadableList应该是更好的选择。 我猜这就是为什么它很少被使用的原因。 - Cory Nelson
不要混淆只读和不可变。想想只读属性,比如Account对象的Balance属性。该属性是只读的,因为它不能通过属性本身进行更改(您不能执行account.Balance = 1000000)。但是该属性可以通过其他机制进行更改,例如account.MakeDeposit(1000000) - Darryl
2个回答

9
它允许您公开只读的“代理”列表,以便您可以将该接口引用传递到其他地方,并知道代码不会改变该列表。(从技术上讲,它可以尝试将其转换回像 List 这样的东西并进行更改,但是它不应该这样做。)
它还允许方法明确指示虽然它需要接受一个列表,但它不会改变它。
拥有只读接口还允许该接口是协变的,不像 List IList

1
不同意第一段。如果您正在返回应保持只读的集合,则应将其包装在实际执行只读的数据结构中,而不仅仅声明返回类型为“IReadOnly”。它最有用作输入参数类型,在这种情况下,您需要可索引但不一定可变的内容(但是您不应该依赖于假设该输入不可变)。它只是一个命名不当的接口。 - nmclean
2
@nmclean 第一段和第二段都在讨论同一个问题,只是从调用者的角度而不是作者的角度来看。调用者正在创建一个只读代理列表,并将其传递给某个东西。 - Servy
如果调用者正在解决相同的问题(确保外部代码不会改变列表),那么我也不同意第二点。如果调用者想要保留对其集合的控制,则在传递之前也应该将其包装起来。IROL参数类型并不是一个承诺,它只是表示所需的最小接口。 - nmclean

1
您可以将其视为子类型化。如果您不修改它,则常规列表可以是只读列表,即List<T>IReadOnlyList<T>的子类型(我不确定C#类型是否实际反映了这一点)。此类型允许您指定特定代码不会对列表进行任何更改。
另一个类似的例子是在C中,您可以将int传递给接受const int的方法,或将int传递给期望volatile int的方法。比所需更严格地处理参数并不会有害。

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