.net C#字典〈>和可变键

b91juud3  于 2023-02-26  发布在  .NET
关注(0)|答案(6)|浏览(181)

有人告诉我,在C#规范中,字符串被设置为不可变的原因之一是为了避免当对字符串键的引用改变了哈希表的内容时,哈希表的键也会改变。
Dictionary〈〉类型允许引用类型用作键。字典如何避免键被更改而导致值“放错地方”的问题?当用作键时,是否存在对象的成员克隆?

bfhwhh0e

bfhwhh0e1#

Dictionary<TKey,TValue>类型没有试图防止用户修改所使用的密钥,它完全由开发人员负责不修改密钥。
如果你稍微考虑一下这个问题,这确实是Dictionary<TKey,TValue>可以采取的唯一明智的方法。考虑一下在对象上执行像成员式克隆这样的操作的含义。为了彻底,你需要执行一个深度克隆,因为键中引用的对象也可能发生变化,从而影响哈希代码。所以现在表中使用的每个键都有它。为了防止变异而克隆的完整对象图。这将是一个有缺陷的操作,而且可能是一个非常昂贵的操作。

67up9zun

67up9zun2#

如果使用可变引用类型作为键,GetHashCode()的默认实现将保证哈希相等,而不考虑对象状态(即哈希绑定到引用,而不是状态)。但是,您是正确的,具有值相等语义的可变类型(GetHashCode可能依赖于状态)是字典键的坏选择。

hrirmatl

hrirmatl3#

Dictionary<>类不会保护自己不受一个可变键对象的改变,你要知道你用作键的类是否是可变的,并尽可能避免它。

irlmq6kh

irlmq6kh4#

如果引用类型不覆盖Equals/GetHashCode,那么使用默认比较器的Dictionary将不关心任何键对象的字段或属性,因此不会注意或关心它们是否改变。最简单的做法是将默认GetHashCode方法看作返回与“对象ID”相关的数字,而将默认Equals方法看作比较“对象ID”。实际上,在一个限制为20亿或更少对象的系统中,GetHashCode可以简单地返回一个对象ID,但由于各种原因,它也可以做其他事情。
如果Equals或GetHashCode只检查对象的ID,那么为了这些函数的目的,所有对象都是不可变的。一旦创建了一个对象,它将始终具有相同的ID,并且该ID将永远不会用于任何其他对象,直到先前对象ID的所有痕迹从Universe中消失。

qvsjd97n

qvsjd97n5#

它不能避免这种情况,而是由调用代码强制执行:
只要对象用作Dictionary<TKey, TValue>中的键,它就不能以任何影响其哈希值的方式进行更改。根据字典的相等比较器,Dictionary<TKey, TValue>中的每个键都必须是唯一的。键不能是null,但如果值类型TValue是引用类型,则值可以是null

  • (从MSDN开始)*
gr8qqesn

gr8qqesn6#

与所有答案相反,通过对记录类的介绍,可以为字典创建可变键。记录类需要使用HashCode结构实现IEqualityComparer。我可以给予一个示例

相关问题