48

在 C# 中,这两个容器之间的主要区别(在功能或用例方面)是什么?Google 上似乎没有任何信息可以比较这些。

System.Collections.ObjectModel.ReadOnlyDictionary System.Collections.Immutable.ImmutableDictionary

我知道 anImmutableDictionary是线程安全的。a 也一样ReadOnlyDictionary吗?

这不是如何正确使用 IReadOnlyDictionary?. 这个问题是关于如何使用 IReadOnlyDictionary。这个问题是关于两者之间的区别(正如有人在 2015 年对该主题评论的那样,这将是一个不同的问题 - 即这个问题)

4

4 回答 4

61
  • AReadOnlyDictionary可以通过构造函数初始化一次,然后您不能从中添加或删除项目(它们会抛出NotSupportedExceptions)。如果您想确保它在跨应用程序的多个层发送时不会被修改,这很有用。
  • AnImmutableDictionary具有修改它的方法,例如Addor Remove,但它们将创建一个新字典并返回它,原始字典保持不变,并返回新的不可变字典的副本。

注意:

  • ReadOnlyDictionary通过将另一个字典实例传递给构造函数来初始化。这就解释了为什么 aReadOnlyDictionary是可变的(如果基础字典被修改)。它只是一个被保护免受直接更改的包装器。
  • 您不能将构造函数用于ImmutableDictionary如何创建 ImmutableDictionary 的新实例?

这也解释了为什么ReadOnlyDictionary不是线程安全的(更好的是:它与底层字典一样线程安全)。这ImmutableDictionary线程安全的,因为您不能修改原始实例(直接或间接)。所有“修改”它的方法实际上都会返回一个新实例。

但是,如果您需要一个线程安全的字典并且它不是不可变的,请使用 aConcurrentDictionary代替。

于 2017-10-24T13:05:01.203 回答
8

AReadOnlyDictionary<TKey,TValue>是另一个现有实现对象的包装器。IDictionary<TKey,TValue>

重要的是,虽然“你”(有权访问 的代码ReadOnlyDictionary)无法通过包装器对字典进行任何更改,但这并不意味着其他代码无法修改底层字典。

因此,与其他答案可能暗示的不同,您不能假设ReadOnlyDictionary不受修改-只是不允许“您”进行修改。因此,例如,您不能确定两次访问特定密钥的尝试会产生相同的结果。

于 2017-10-24T13:20:06.420 回答
0

ReadOnlyDictionary: 是ReadOnly,不能添加或删除

ImmutableDictonary: 可以添加或删除,但它像字符串一样不可变。有新对象要添加和删除。

于 2017-10-24T13:14:50.337 回答
-1

与其描述这两个类的作用,不如描述它对于只读或不可变的实际意味着什么,因为有一个关键区别并没有真正为这两个实现提供太多选择。

只读是类的“接口”的一部分,它的公共方法和属性集。只读意味着该类的外部使用者无法执行任何可能的操作序列来影响其可见状态。例如,与只读文件进行比较;没有应用程序可以使用相同的 API 写入这样的文件,这使得它首先成为只读的成为可能。

只读是否意味着线程安全?不一定——只读类仍然可以使用诸如缓存或优化其内部数据结构之类的东西,并且这些东西可能(很差)以一种在同时调用时会中断的方式实现。

只读是否意味着永远不变?也没有;例如,查看系统时钟。您不能真正影响它(使用默认权限),您只能读取它(根据定义使其为只读),但它的值会根据时间而变化。

永不改变意味着不变。这是一个更强大的概念,并且像线程安全一样,是整个类契约的一部分。类必须主动确保其实例的任何部分在其生命周期内都不会改变,就可以从外部观察到的内容而言。

字符串在 .NET 中是不可变的:只要运行时的完整性没有受到损害(通过内存黑客),字符串的特定实例永远不会与其最初观察到的值不同。另一方面,只读文件并不是不可变的,因为人们总是可以关闭只读并更改文件。

不可变也不意味着线程安全,因为这样的对象仍然可以使用修改其内部状态并且不是线程安全的技术(但通常更容易确保)。

不可变是否意味着只读的问题取决于您如何看待它。您通常可以以不影响可能正在使用它的外部代码的方式“改变”不可变对象,因此公开不可变对象至少与公开只读对象一样强。获取字符串的子字符串就像删除其中的一部分,但以安全的方式。


这让我们回到了关于这两个类的原始问题。ReadOnlyDictionary所要做的就是只读。您仍然必须以某种方式提供数据,使用内部包装的字典,并且只有您自己仍然可以通过内部字典写入数据。包装器提供“强”只读访问(与您通过转换为IReadOnlyDictionary获得的“弱”只读访问相比)。它也是线程安全的,但前提是底层字典也是线程安全的。

ImmutableDictionary可以做更多的事情,因为它拥有的数据不能被更改。本质上,您可以用新数据“修补”其中的一部分并获得结构的修改“副本”,但实际上无需复制完整的对象。由于其实现,它也是线程安全的。与StringBuilder类似,您使用构建器对实例进行更改,然后烘焙它们以生成不可变字典的最终实例。

于 2021-08-23T12:06:20.457 回答