【问题标题】:C# Dictionary<> and mutable keysC# Dictionary<> 和可变键
【发布时间】:2011-03-01 17:46:57
【问题描述】:

有人告诉我,在 C# 规范中将字符串设为不可变的众多原因之一是为了避免 HashTable 在对字符串键的引用更改其内容时更改键的问题。

Dictionary 类型允许将引用类型用作键。字典如何避免导致“错位”值的更改键的问题?当用作键时,是否存在由对象组成的成员克隆?

【问题讨论】:

    标签: c# .net dictionary hashtable


    【解决方案1】:

    如果引用类型不覆盖 Equals/GetHashCode,则使用默认比较器的字典不会关心任何关键对象的字段或属性,因此不会注意到或关心它们是否发生变化。最简单的方法是将默认的 GetHashCode 方法视为返回与“对象 ID”相关的数字,将默认的 Equals 方法视为比较“对象 ID”。实际上,在一个对象限制为 20 亿或更少的系统中,GetHashCode 可以简单地返回一个对象 ID,但由于各种原因,它也可能做其他事情。

    如果由 Equals 或 GetHashCode 检查的对象的唯一部分是对象 ID,那么就这些函数而言,所有对象都是不可变的。一旦创建了一个对象,它将始终具有相同的 ID,并且在前一个对象 ID 的所有痕迹从 Universe 中消失之前,该 ID 将永远不会用于任何其他对象。

    【讨论】:

      【解决方案2】:

      如果您使用可变引用类型作为键,GetHashCode() 的默认实现将保证哈希相等,而不管对象状态如何(即哈希与引用相关联,而不是状态)。但是,您是对的,具有值相等语义(其中 GetHashCode 可能取决于状态)的可变类型对于字典键来说是一个糟糕的选择。

      【讨论】:

      • 这个不错。感谢您记得我默认情况下对象的 GetHashCode 是基于实例的,我认为这可以为开发人员节省大量时间。
      • 具有值相等语义的可变类类型似乎是个坏主意。虽然有一些例外(例如doubleDecimalList&lt;T&gt;.Enumerator 等),但.net 中的大多数类型都实现了Equals(Object) 以表示等价;由于不同的可变类类型项永远不会等价,因此它们永远不应将自己报告为EqualsList&lt;T&gt;.Enumerator 的行为源于装箱和未装箱的值类型具有不同的语义,但需要共享相同的 @987654328 @方法)。
      【解决方案3】:

      它并没有避免这种情况。由调用代码来强制执行此操作:

      只要将对象用作Dictionary&lt;TKey, TValue&gt; 中的键,它就不能以任何影响其哈希值的方式发生变化。根据字典的相等比较器,Dictionary&lt;TKey, TValue&gt; 中的每个键都必须是唯一的。键不能是null,但值可以是,如果值类型TValue 是引用类型。

      (来自MSDN

      【讨论】:

        【解决方案4】:

        Dictionary&lt;TKey,TValue&gt; 类型不会尝试防止用户修改所使用的密钥。完全由开发人员负责不改变密钥。

        如果您仔细考虑一下,这确实是唯一合理的方法 Dictionary&lt;TKey,TValue&gt;可以拿。考虑在对象上执行类似成员克隆的操作的含义。为了彻底,您需要进行深度克隆,因为键中引用的对象也可能发生变异,从而影响哈希码。因此,现在表中使用的每个键都克隆了完整的对象图,以防止突变。这将是错误的,并且可能是一项非常昂贵的操作。

        【讨论】:

        【解决方案5】:

        Dictionary&lt;&gt; 类不会保护自己免受可变键对象的更改。由您决定您用作键的类是否是可变的,并尽可能避免它。

        【讨论】:

          猜你喜欢
          • 2011-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多