.NET 4.5有一个新的命名空间System.Collections.Immutable
该包提供了线程安全且保证永远不会更改其内容的集合,也称为不可变集合。
我感到困惑。 ReadOnlyCollection类已经解决了线程安全问题,为什么要使用ImmutableList呢?
我知道还有一个IReadOnlyList 接口。这并不能隐式解决线程安全问题,因为其他线程可能会通过另一个接口编辑对象。
.NET 4.5有一个新的命名空间System.Collections.Immutable
该包提供了线程安全且保证永远不会更改其内容的集合,也称为不可变集合。
我感到困惑。 ReadOnlyCollection类已经解决了线程安全问题,为什么要使用ImmutableList呢?
我知道还有一个IReadOnlyList 接口。这并不能隐式解决线程安全问题,因为其他线程可能会通过另一个接口编辑对象。
ImmutableList
,任何人都可以通过非托管路线更改该内存位置的内容而不被 CLR 感知。但是只要所有各方遵守 .Net 平台提供的法律条款,我们就可以安全地认为 ImmutableList
确实是不可变的。 - RBTImmutableList
的正确公共API,则没有基础集合可供修改 - 当您调用Add
等时,它会返回带有添加内容的集合的新副本 - 原始版本保持不变。对于ReadOnlyCollection
,虽然您无法通过该类本身修改它,但仍然可以修改使用ReadOnlyCollection
初始化的基础集合。如果您开始使用反射或其他修改数据的方法,那么是的 - 任何事都可以像我之前的评论一样。 - James ThorpeReadOnlyCollection<T>
不能解决任何线程安全问题,它只是IList<T>
的包装器。它不公开修改集合的成员,但您始终可以使用底层集合引用来修改它。
如果底层集合被修改,则枚举ReadOnlyCollection<T>
不安全。如果这样做,您将获得相同的InvalidOperationException
和消息“Collection was modified; enumeration operation may not execute...”。
ReadOnlyCollection可以支持多个读者同时访问,只要不修改集合。即使如此,枚举集合本质上不是线程安全的过程。为了保证枚举期间的线程安全性,您可以在整个枚举过程中锁定集合。要允许多个线程对其进行读写访问,必须实现自己的同步。
另一方面,ImmutableList
是不可变的,因此本质上是线程安全的。
ReadOnlyCollection
只能读取数据,正如其名称所示。
另一方面,您可以通过调用Add
/Remove
/Clear
等方法来向ImmutableList
添加/删除项目,这些方法将返回一个新的不可变列表。
ImmutableList<>
非常类似于一个 string
。 - xanatosReadOnlyCollection<T>
文档:List<T>
和其他集合一样,不是线程安全的,因此只读集合也不是线程安全的。ReadOnlyCollection<T>
中的List<T>
,并且仅使用getter,在多线程环境中仍可能发生崩溃!ReadOnlyCollection
中,也不能直接在多线程环境中使用。ReadOnlyCollection
相反,不可变集合确保在获得对集合的引用之后,不会更改任何内部结构。请注意,这些结构仍然不是真正的不可变。它们代替是可冻结的。这意味着结构将在内部更改一段时间,直到被冻结并返回给调用者。超过该点后,对不可变集合的所有其他调用只会在原始引用中访问的结构之外进行修改。到目前为止,所有的技术细节都讲解完毕,但是并没有代码。
我创建了一个小例子来展示主要区别。
考虑在这种情况下,将只读集合和不可变列表指向同一对象"字符串列表"。
如果我们在只读集合创建后向"字符串列表"添加新项,我们可以看到只读集合被修改。(所以我们设法找到了一种改变只读集合的方法)
然而,当我们在不可变列表上采取相同的步骤时,不可变列表保持不变。
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);
}
strings.Add("Visual Studio 2022");
没有任何效果,因为调用的结果被忽略了。 - Theodor ZouliasimmutableList.Add("Visual Studio 2022");
。你可以考虑在回答中添加更多文本,解释代码应该展示什么。目前它更像是一个谜题而不是一个有用的答案。 - Theodor ZouliasReadOnlyCollection
在每次进行修改时需要创建一个完全独立的集合副本。”--为什么?为什么要创建一个副本,而不是直接修改集合呢?集合的所有者始终可以对其进行修改。只有只读外观的用户无法改变集合。” - Theodor Zoulias
System.Collections.Immutable
必须通过 NuGet 包管理器安装。我在一个针对 .Net Framework 4.6.2 的项目中不得不这样做。 - RBT