【问题标题】:What's the difference between a ReadOnlyDictionary and an ImmutableDictionary?ReadOnlyDictionary 和 ImmutableDictionary 有什么区别?
【发布时间】:2017-10-24 12:57:06
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您只能从ReadOnlyDictionary 中读取。 ImmutableDictionary 允许您执行 add 和 clear 之类的操作,但不是更改字典,而是创建一个带有更改的新字典。
  • juharr 说的。并且进一步扩展,只读集合将始终是线程安全的,特别是因为您不能更新值,也不能添加到它。
  • 绝对错误!仅仅因为字典的使用者不能更新它并不意味着它是线程安全的。底层字典的所有者可以更新它,在这种情况下,它根本不是线程安全的。 (MSDN:不保证任何实例成员都是线程安全的。)
  • 这能回答你的问题吗? How to properly use IReadOnlyDictionary?
  • 不,抱歉,它没有回答这个问题。这个问题是关于如何使用 IReadOnlyDictionary。这个问题是关于两者之间的区别(正如 2015 年有人在该帖子中评论的那样,这将是一个不同的问题 - 即这个问题)

标签: c# .net immutable-collections


【解决方案1】:
  • ReadOnlyDictionary 可以通过构造函数初始化一次,然后您就不能从中添加或删除项目(它们会抛出 NotSupportedExceptions)。如果您想确保它在跨应用程序的多个层发送时不会被修改,这将非常有用。
  • ImmutableDictionary 具有修改它的方法,如 AddRemove,但它们将创建一个新字典并返回它,原始字典保持不变,并返回新不可变字典的副本。李>

注意:

  • 您通过将另一个字典实例传递给constructor 来初始化ReadOnlyDictionary。这就解释了为什么 ReadOnlyDictionary 是可变的(如果修改了基础字典)。它只是一个防止直接更改的包装器。
  • 您不能为ImmutableDictionary 使用构造函数:How can I create a new instance of ImmutableDictionary?

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

但是,如果您需要一个线程安全的字典并且它不一定是不可变的,请改用ConcurrentDictionary

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      ReadOnlyDictionary:是ReadOnly,无法添加或删除

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

      【讨论】:

        【解决方案4】:

        与其描述这两个类的作用,不如描述只读或不可变的实际含义,因为有一个关键区别并没有真正为这两个实现提供太多选择.

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

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

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

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

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

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

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


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

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

        【讨论】:

          猜你喜欢
          • 2018-07-18
          • 2016-12-29
          • 2010-10-02
          • 2011-12-12
          • 2010-09-16
          • 2012-03-14
          • 2012-02-06
          • 2011-02-25
          • 2011-11-22
          相关资源
          最近更新 更多