.net 为什么要使用ImmutableList而不是ReadOnlyCollection?

ggazkfy8  于 2022-11-19  发布在  .NET
关注(0)|答案(6)|浏览(167)

.NET 4.5具有新的命名空间System.Collections.Immutable
此包提供线程安全的集合,并保证永远不会更改其内容,也称为不可变集合。
我很困惑。线程安全问题不是已经被ReadOnlyCollection类解决了吗?为什么要用ImmutableList来代替?
我知道还有一个IReadOnlyList interface,这并没有隐式地解决线程安全问题,因为其他线程可能会通过另一个接口编辑该对象。

hyrbngr7

hyrbngr71#

使用ReadOnlyCollection
只读的集合只是具有防止修改集合的 Package 的集合;因此,如果对基础集合进行了更改,则只读集合将反映这些更改。
ImmutableList不会发生这种情况。

5lhxktic

5lhxktic2#

ReadOnlyCollection<T>并不能解决任何线程安全问题。它只是Ilist<T>的一个 Package 器。它并不公开成员来修改集合,但是你总是可以用基础集合引用来修改它。
如果底层集合被修改,枚举ReadOnlyCollection<T>是不安全的。如果这样做,您将得到相同的InvalidOperationException,并显示消息“Collection was modified;枚举操作可能无法执行..."
ReadOnlyCollection<T>开始
ReadOnlyCollection可以同时支援多个读取器,只要该集合未被修改即可。即使如此,枚举整个集合本质上并不是执行绪安全的程序。若要保证枚举期间的执行绪安全,您可以在整个枚举期间锁定集合。若要允许多个执行绪存取集合以进行阅读和写入,您必须实作自己的同步行程。
另一方面,ImmutableList是不可变的,因此本质上是线程安全的。

vbkedwbf

vbkedwbf3#

ReadOnlyCollection,顾名思义,只能读取。
另一方面,您可以通过调用Add/Remove/Clear方法(例如,这些方法返回一个新的不可变列表)向ImmutableList添加项或从ImmutableList删除项。

czq61nw1

czq61nw14#

在多执行绪案例中,请注意只读集合仍然不是执行绪安全的。
ReadOnlyCollection<T>文档中:
...如果对基础集合进行了更改,则只读集合将反映这些更改
因为集合(例如List<T>和其他集合)不是执行绪安全的,所以不是只读集合。

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

底线是,即使将公共集合 Package 到ReadOnlyCollection中,也不能在开箱即用的多线程环境中使用。
ReadOnlyCollection相反,不可变集合保证在获得对集合的引用后,内部结构不会发生任何变化。注意,这些结构仍然不是真正的不可变。相反,它们是 freezable。这意味着结构将在内部变化一段时间,直到它被 * freezable * 并返回给调用者。超过这一点,对不可变集合的所有其他调用将仅在可通过原始引用访问的结构之外进行修改。
结论:只读集合 * 不是 * 线程安全的;不可变集合是线程安全的。

7jmck4yq

7jmck4yq5#

主要的好处是内存效率,而不是线程安全。
System.Collections.Immutable中的不可变集合的设计方式允许修改后的集合与同一集合的未修改副本共享数据结构。这些差异以巧妙的方式编码,不需要复制整个数据结构。在Immutable Collections中对此有很好的解释。
ReadOnlyCollection要求每次进行修改时都创建一个完全独立的集合副本。这会占用更多内存,并给垃圾收集器带来更高的负载。
正如您所观察到的,这两个类都试图保证集合不会有可观察到的修改。

uurv41yg

uurv41yg6#

到目前为止,所有的技术方面都被告知,但没有代码。我创建了一个小例子显示主要的区别。

List<string> strings = new List<string>()
{
    "Visual Studio 2017","Visual Studio 2019"
};
ReadOnlyCollection<string> readOnlyStrings = strings.AsReadOnly();
var immutableList = strings.ToImmutableList();
strings.Add("Visual Studio 2022");
Console.WriteLine("Readonly List");

foreach (string item in readOnlyStrings)
{
    Console.WriteLine(item);
}
Console.WriteLine("Immutable List");

foreach (string item in immutableList)
{
    Console.WriteLine(item);
}

相关问题