List<T>.AsReadOnly() 与 IReadOnlyCollection<T>

Posted

技术标签:

【中文标题】List<T>.AsReadOnly() 与 IReadOnlyCollection<T>【英文标题】:List<T>.AsReadOnly() vs IReadOnlyCollection<T> 【发布时间】:2013-06-28 05:13:11 【问题描述】:

List&lt;T&gt; 实现IReadOnlyCollection&lt;T&gt; 接口并提供AsReadOnly() 方法,该方法返回ReadOnlyCollection&lt;T&gt;(该方法又实现IReadOnlyCollection&lt;T&gt;)。

AsReadyOnly() 的用途/原因是什么?它的存在有一种或两种极端情况的味道,其中仅将列表返回为IReadOnlyCollection&lt;T&gt; 还不够好。

起初我虽然可能是为了防止消除成本,但看起来你可以使用ReadOnlyCollection&lt;T&gt;Items 访问器来做到这一点。

顺便说一句。 ReadOnlyCollection&lt;T&gt; 类型的文档为

为通用只读集合提供基类。

在我看来,这与将构造函数描述为

初始化 (...) 类的新实例,该实例是指定列表的只读包装器。

更新: 我没有看到ReadOnlyCollection&lt;T&gt;Items 受到保护。

【问题讨论】:

我更喜欢.ToArray()。更简单的海事组织! @KierenJohnstone 也可能更慢。 .ToArray() 创建了一个全新的数组,因此速度较慢,而且数组是可变的,这意味着它的任何元素都可以更改。 .AsReadOnly() 更快,消费者不能通过改变单个元素来改变它。但是,当原始列表发生变化时,它确实会发生变化。 【参考方案1】:

如果您只是将实际的List&lt;T&gt; 作为IReadOnlyList&lt;T&gt; 返回,那么调用者总是可以将其转换回,然后根据需要修改列表。相反,调用AsReadOnly() 会创建一个只读的列表包装器,消费者无法对其进行更新。

请注意,只读包装器将反映对基础列表所做的更改,因此可以访问原始列表的代码仍然可以在知道只读版本的任何消费者将看到这些更改的情况下对其进行更新。

【讨论】:

但是我可以回退AsReadOnly().Items,不是吗? @Tymek 你不能:AsReadOnly() 创建一个新的非List&lt;T&gt; 类,它没有允许基础列表突变的公共方法。 (Itemsprotected,所以随机消费者无法访问它。) @Steven Items 是原始列表,但我现在才注意到它受到保护。哇! 还要注意 List.AsReadOnly() 方法自 .NET 2.0 起就存在,而 IReadOnlyCollection 接口是 .NET 4.5 中的新接口。所以这里的 API 可能会有些重叠,但 AsReadOnly 仍然有用。 @Steven 是的,AsReadonly 从 .NET 2.0 开始总是返回 ReadonlyCollection&lt;T&gt;,只是 ReadonlyCollection&lt;T&gt; 最近实现了 IReadonlyCollection&lt;T&gt;【参考方案2】:

首先,添加 AsReadOnly() 并不是因为 IReadOnlyList&lt;T&gt; 不够好——IReadOnlyList&lt;T&gt; 仅从 .NET 4.5 开始可用,而 AsReadOnly() 方法从 .NET 2 开始存在。

更重要的是:AsReadOnly()IReadOnlyList&lt;T&gt; 的用途截然不同。

ReadOnlyCollection&lt;T&gt; 用于实现对象模型,例如Dictionary&lt;K,V&gt;.KeysDictionary&lt;K,V&gt;.Values。这适用于消费者不应该能够更改内容而生产者可以更改内容的场景。它与Collection&lt;T&gt; 协同工作,后者为所有者提供挂钩以在添加项目时验证更改或执行副作用。

另一方面,IReadOnlyList&lt;T&gt; 只是一个提供集合只读视图的接口。方法可以使用它来表示“我需要一个随机访问集合,但我不需要能够修改它”。例如,BinarySearch 方法可能如下所示:

public int BinarySearch<T>(IReadOnlyList<T> list, int start, int length);

为了使这个方法有用,它需要能够传入任何列表。强制创建包装器集合会非常昂贵。

【讨论】:

以上是关于List<T>.AsReadOnly() 与 IReadOnlyCollection<T>的主要内容,如果未能解决你的问题,请参考以下文章

检查List的元素是否等于输入

根据键将 List<List<List<T>>> 转换为 List<List<T>>

Java 流:将 List<T> 转换为 List<List<T>>

为啥我在 List<List<T>> 中复制 List<T> 时存在依赖关系? [复制]

在 C# 中将 List<List<T>> 转换为 List<T>

从 List<OwnStruct> 返回 List<T> 的方法,其中 List<T> 仅包含 List 中所有 OwnStructs 的一个属性(C#)[重复]