Kal*_*son 12 .net c# dictionary hashcode immutability
将对象添加到.NET System.Collections.Generic.Dictionary类时,密钥的哈希码将在内部存储并用于以后的比较.当哈希码在其初始插入字典后发生变化时,它经常变得"不可访问",并且当存在检查(即使使用相同的引用)返回false时,它可能会使其用户感到惊讶(下面的示例代码).
该GetHashCode的文件说:
为对象GetHashCode方法必须一致,只要没有修改确定的该对象的Equals方法返回值的对象的状态返回相同的散列码.
因此,根据GetHashCode文档,只要更改了相等的确定状态,哈希码就会改变,但Dictionary实现不支持这一点.
当前的.NET字典实现是否被打破,因为它错误地忽略了哈希码限额?应该GetHashCode()只基于不可变成员?或者,还有什么可以打破可能的错误二分法吗?
class Hashable
{
public int PK { get; set; }
public override int GetHashCode()
{
if (PK != 0) return PK.GetHashCode();
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Hashable);
}
public virtual bool Equals(Hashable other)
{
if (other == null) return false;
else if (ReferenceEquals(this, other)) return true;
else if (PK != 0 && other.PK != 0) return Equals(PK, other.PK);
return false;
}
public override string ToString()
{
return string.Format("Hashable {0}", PK);
}
}
class Test
{
static void Main(string[] args)
{
var dict = new Dictionary<Hashable, bool>();
var h = new Hashable();
dict.Add(h, true);
h.PK = 42;
if (!dict.ContainsKey(h)) // returns false, despite same reference
dict.Add(h, false);
}
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 27
不,你不应该在将它插入字典后改变键(以物质方式).这是设计,以及我曾经使用的每个哈希表的工作方式.文档甚至指定了这个:
只要将对象用作其中的键
Dictionary<TKey, TValue>,就不得以任何影响其哈希值的方式进行更改.Dictionary<TKey, TValue>根据字典的相等比较器,a中的每个键必须是唯一的.如果值类型TValue是引用类型,则键不能为null,但值可以为.
所以它只会给那些不阅读文档的用户带来惊喜:)
要添加Jon的答案,我只想强调你引用的文档的某个部分:
只要没有对对象状态的修改来确定对象的Equals方法的返回值,对象的 GetHashCode方法必须始终返回相同的哈希代码 .
现在,就在那里,你违反了规则.你改变了PK,这不会影响结果Equals(因为你有那个ReferenceEquals检查),但你的结果GetHashCode 确实改变了.这就是简单的答案.
采用更概念化的方法,我认为你可以这样看:如果你已经覆盖了你的类型Equals和GetHashCode行为,那么你已经掌握了这个类型的一个实例对于它的意义的概念.另一个.事实上,你已经以一种Hashable对象可以变成完全不同的方式来定义它; 即,不再像以前那样使用的东西(因为它的哈希码已经改变).
从这个角度考虑,在你做完dict.Add(h, true)之后再进行更改时h.PK,字典不再包含被引用的对象h.它包含其他东西(在任何地方都不存在).它有点像你定义的类型是一条脱落皮肤的蛇.
| 归档时间: |
|
| 查看次数: |
1782 次 |
| 最近记录: |