为什么在ReadOnlyCollection上使用ImmutableList?

时间:2015-05-11 10:52:56

标签: c# .net immutable-collections

.NET 4.5有一个新的命名空间System.Collections.Immutable

  

此软件包提供线程安全的集合,并保证永远不会更改其内容,也称为不可变集合。

我很困惑。是不是ReadOnlyCollection类已经解决了线程安全问题?为什么要使用ImmutableList

我知道那里还有IReadOnlyList interface。这并没有隐含地解决线程安全问题,因为其他线程可能会通过另一个接口编辑该对象。

4 个答案:

答案 0 :(得分:54)

使用ReadOnlyCollection

  

只读集合只是一个带有包装器的集合   这会阻止修改集合;因此,如果做出改变   对于底层集合,只读集合反映了这些集合   变化。

使用ImmutableList时不会发生这种情况。

答案 1 :(得分:21)

ReadOnlyCollection<T>无法解决任何线程安全问题。它只是Ilist<T>的包装器。它不会公开成员来修改集合,但是你总是可以使用底层集合引用来修改它。

如果修改了基础集合,则枚举ReadOnlyCollection<T>是不安全的。如果你这样做,你将获得相同的InvalidOperationException消息&#34;收集被修改;枚举操作可能无法执行...&#34;。

来自ReadOnlyCollection<T>

  

ReadOnlyCollection可以同时支持多个读者,如   只要不修改集合。即便如此,通过一个列举   集合本质上不是一个线程安全的过程。保证   枚举期间的线程安全性,您可以在锁定期间锁定集合   整个枚举。允许访问集合   多个线程用于读写,你必须实现自己的   同步。

另一方面,

ImmutableList是不可变的,因此本质上是线程安全的。

答案 2 :(得分:12)

ReadOnlyCollection,顾名思义,只能阅读。

另一方面,您可以通过调用ImmutableList / Add / Remove方法向Clear追加/删除项目,例如返回一个新的不可变列表。

答案 3 :(得分:4)

在多线程方案中,请注意只读集合仍然不是线程安全的。

来自ReadOnlyCollection<T>文档:

  

...如果对基础集合进行了更改,则只读集合会反映这些更改

由于集合(如List<T>和其他集合)不是线程安全的,因此不是只读集合。

重要:在MSDN中,您找不到明确解释的一些极端情况。一些看似只读取集合内容的操作实际上正在修改集合的内部结构。为什么没有指定? - 一个明显的原因是因为这是一个不反映API的实现细节。结果是,即使您不修改包含在List<T>中的ReadOnlyCollection<T>,并且仅使用getter,崩溃仍可能发生在多线程环境中!

底线是常见的集合,即使被包装成ReadOnlyCollection也无法在开箱即用的多线程环境中使用。

ReadOnlyCollection相反,不可变集合确保在获得对集合的引用后,任何内部结构都不会发生变化。请注意,这些结构仍然不是真正不可变的。相反,它们是 freezable 。这意味着结构将在内部更改一段时间,直到冻结并返回给调用者。除此之外,对不可变集合的所有其他调用只会在通过原始引用可访问的结构之外进行修改。

结论:只读集合线程安全;不可变集合是线程安全的。

相关问题