在C#Dictionary中使用基线对象GetHashCode:no-no?

时间:2014-05-05 01:17:53

标签: c# dictionary

我试图将.Net库与由API类的许多实例生成的异步回调一起使用,并且在我的事件处理程序中,我需要找到此特定事件来自哪个实例,以及关于其背景的所有信息。

第一部分很简单,因为回调的第一个参数将是发送通知的对象,只需要转换。但现在我一直在寻找一种方法将它与我自己的数据相关联,因为该对象只有很少的公共属性来识别实例。

此刻,我宣布......

Dictionary<TheDotNetClass,MyClass> 

..它看起来似乎没问题,但我怀疑它只是使用通用的Object.getHashCode / compare而且它可能远非安全,可能会随着时间的推移而改变,会导致方式太多的碰撞等等。

然而,我无法想到任何可以帮助我连接通用对象的替代方案,我将获得与我身边的API实例相关联的所有元数据。

我忽略了什么吗?我做的安全到足以扩展吗?谢谢!

2 个答案:

答案 0 :(得分:2)

默认EqualsGetHashCode基于引用相等性。如果对象没有覆盖EqualsGetHashCode(您可以使用dotPeek之类的反编译器进行验证),那么每个对象实例都将是一个唯一的字典键,所以是的,你可以使用Dictionary将额外数据附加到每个实例。这是一个相当常见的场景,它完全受支持 - 您正在按设计使用它。

我不担心哈希冲突。 BCL团队很聪明;他们将基础GetHashCode设计为用作哈希键,因此冲突应该是最小的。

编辑:这是一段代码片段,显示哈希码不是基于对象的地址。压缩后,b的地址将发生变化,但请注意其哈希码不会。

var a = new object();
var originalHashCodeA = a.GetHashCode();
for (var i = 0; i < 10000; ++i)
    new object();
var b = new object();
var originalHashCodeB = b.GetHashCode();

// Synchronous garbage collection (see http://stackoverflow.com/q/748777/87399)
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

Console.WriteLine(a.GetHashCode() == originalHashCodeA);
Console.WriteLine(b.GetHashCode() == originalHashCodeB);

请注意,输出为TrueTrue。垃圾收集和压缩后,对象的哈希码都没有改变。所以,是的,默认的GetHashCode在压缩过程中是安全的。

答案 1 :(得分:0)

这种方法很好。两个哈希码匹配的唯一时间(假设类正确实现)是Object.Equals返回true时。

如果该函数返回true,那么我会想象你想要&#34;碰撞&#34;因为它们实际上是同一个对象而发生。请注意,在使用自定义类时,建议您为此目的覆盖.Equals.GetHashCode