代码之家  ›  专栏  ›  技术社区  ›  Pierreten

字典和可变键

  •  8
  • Pierreten  · 技术社区  · 16 年前

    有人告诉我,在C规范中,字符串不可变的许多原因之一是为了避免哈希表的问题,即当对字符串键的引用更改了其内容时,键发生了更改。

    字典类型允许将引用类型用作键。字典如何避免出现导致“错位”值的更改键?当用作密钥时,是否存在由对象构成的MemberWise克隆?

    5 回复  |  直到 14 年前
        1
  •  9
  •   JaredPar    16 年前

    这个 Dictionary<TKey,TValue> 类型不会试图防止用户修改所使用的键。完全由开发人员负责不改变密钥。

    如果你稍微考虑一下,这真的是唯一一条理智的路线 字典<tkey,tvalue> 可以采取。考虑在对象上执行类似于memberwise克隆的操作的含义。为了彻底起见,您需要进行深度克隆,因为密钥中引用的对象也可能发生变异,从而影响哈希代码。所以现在表中使用的每一个键都克隆了它的完整对象图,以防止发生变异。这将是一个小车,可能是一个非常昂贵的操作。

        2
  •  8
  •   Dan Bryant    16 年前

    如果使用可变引用类型作为键,则 GetHashCode() 将保证哈希相等,而不考虑对象状态(即哈希绑定到引用,而不是状态)。但是,您是正确的,对于字典键来说,具有值相等语义(gethashcode可能取决于状态)的可变类型是一个错误的选择。

        3
  •  5
  •   JSBÕ±Õ¸Õ£Õ¹    16 年前

    这个 Dictionary<> 类不做任何事情来保护自己不受可变键对象被更改的影响。这取决于你是否知道你作为一个键使用的类是可变的,如果可能的话避免它。

        4
  •  3
  •   Anton Gogolev    16 年前

    这并不能避免这种情况。这取决于调用代码来强制执行:

    只要对象用作 Dictionary<TKey, TValue> ,它不能以任何方式更改影响其哈希值。A中的每个键 字典<tkey,tvalue> 根据字典的相等比较器,必须是唯一的。密钥不能 null ,但如果值类型为 TValue 是引用类型。

    (从 MSDN )

        5
  •  3
  •   supercat    14 年前

    如果引用类型不重写equals/gethashcode,则使用默认比较器的字典将不关心任何键对象的字段或属性,因此不会注意或关心它们是否更改。最简单的方法是将默认的gethashcode方法看作返回与“object id”相关的数字,将默认的equals方法看作比较“object id”的方法。实际上,在一个限制为20亿或更少对象的系统中,gethashcode可以简单地返回一个对象ID,但出于各种原因,它也可以做其他事情。

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