为什么在ReadOnlyCollection上使用ImmutableList?

Col*_*nic 51 .net c# immutable-collections

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

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

我糊涂了.是不是ReadOnlyCollection类已经解决了线程安全问题?为什么要使用ImmutableList呢?


我知道还有一个IReadOnlyList 接口.这并不能隐式解决线程安全问题,因为其他线程可能会通过另一个接口编辑该对象.

Jam*_*rpe 55

ReadOnlyCollection:

只读集合只是一个带有包装器的集合,可以防止修改集合; 因此,如果对基础集合进行了更改,则只读集合会反映这些更改.

这不可能发生ImmutableList.

  • @RBT对于任何程序都是一样的 - 如果你在相同的进程中运行代码,操作系统不会阻止你改变任何东西 (13认同)
  • 我建议不可变集合最重要的特性是如何通过创建新的不可变集合和底层有效的"写时复制"机制来操纵它们.因此,其他两个答案似乎与我更相关. (5认同)

Sri*_*vel 22

ReadOnlyCollection<T>没有解决任何线程安全问题.它只是一个包装Ilist<T>.它不会公开成员来修改集合,但您始终可以使用基础集合引用对其进行修改.

如果修改了基础集合,则枚举它是不安全的ReadOnlyCollection<T>.如果您这样做,您将得到相同InvalidOperationException的消息"集合已被修改;枚举操作可能无法执行...".

ReadOnlyCollection<T>

只要未修改集合,ReadOnlyCollection就可以同时支持多个读取器.即便如此,通过集合枚举本质上不是一个线程安全的过程.为了在枚举期间保证线程安全,您可以在整个枚举期间锁定集合.要允许多个线程访问集合以进行读写,您必须实现自己的同步.

ImmutableList 另一方面,它是不可变的,因此本质上是线程安全的.


dca*_*tro 17

ReadOnlyCollection顾名思义,只能阅读.

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

  • 我要补充一点,这使得`ImmutableList <>`非常类似于`string`. (9认同)
  • 使用 ImmutableList,不是重要的区别,就像字符串一样,您没有修改原始内容。您正在创建一个带有更改的新对象(例如使用 Remove),但原始版本保持不变? (2认同)

Zor*_*vat 10

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

ReadOnlyCollection<T>文档中:

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

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

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

最重要的是,即使包装到一个通用集合中,也ReadOnlyCollection不能在多线程环境中开箱即用。

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

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