为什么两个委托实例返回相同的哈希码?
本文关键字:返回 哈希码 实例 两个 为什么 | 更新日期: 2023-09-27 18:01:45
以以下内容为例:
var x = new Action(() => { Console.Write("") ; });
var y = new Action(() => { });
var a = x.GetHashCode();
var b = y.GetHashCode();
Console.WriteLine(a == b);
Console.WriteLine(x == y);
这将打印:
True
False
为什么哈希码是相同的?
这有点令人惊讶,并且会使在Dictionary
中使用委托与List
(也称为O(n)
查找)一样慢。
更新:
问题是为什么。谁做了这样(愚蠢)的决定?
一个更好的hashcode实现应该是:
return Method ^ Target == null ? 0 : Target.GetHashcode();
// where Method is IntPtr
轻松!因为这里是GetHashCode
的实现(位于基类Delegate
上):
public override int GetHashCode()
{
return base.GetType().GetHashCode();
}
(位于将在上面调用的基类MulticastDelegate
上):
public sealed override int GetHashCode()
{
if (this.IsUnmanagedFunctionPtr())
{
return ValueType.GetHashCodeOfPtr(base._methodPtr);
}
object[] objArray = this._invocationList as object[];
if (objArray == null)
{
return base.GetHashCode();
}
int num = 0;
for (int i = 0; i < ((int) this._invocationCount); i++)
{
num = (num * 0x21) + objArray[i].GetHashCode();
}
return num;
}
使用Reflector之类的工具,我们可以看到代码,它的默认实现看起来就像我们上面看到的奇怪的。
此处的type值为Action
。因此上面的结果是正确的。
我第一次尝试更好的实现:
public class DelegateEqualityComparer:IEqualityComparer<Delegate>
{
public bool Equals(Delegate del1,Delegate del2)
{
return (del1 != null) && del1.Equals(del2);
}
public int GetHashCode(Delegate obj)
{
if(obj==null)
return 0;
int result = obj.Method.GetHashCode() ^ obj.GetType().GetHashCode();
if(obj.Target != null)
result ^= RuntimeHelpers.GetHashCode(obj);
return result;
}
}
此质量对于单类型转换委托应该是好的,但对于多播委托就不那么好了(如果我没记错的话,Target/Method返回最后一个元素委托的值)。
但是我真的不确定它是否在所有的情况下都履行了合同。
嗯,看起来质量要求参照相等的目标。
这闻起来像这个线程中提到的一些情况,也许它会给你一些关于这种行为的指针。否则,您可以在这里记录:-)
你在c#或。net中见过的最奇怪的角落案例是什么?
Rgds GJ
From MSDN:
的默认实现GetHashCode不保证独特性或一致性;因此,它不能作为唯一对象使用用于散列目的的标识符。派生类必须重写GetHashCode和实现返回唯一的哈希码。为最好的结果,哈希码必须是根据实例的值字段或属性,而不是静态字段或属性。
所以如果你没有重写GetHashCode方法,它可能会返回相同的值。我怀疑这是因为它是从定义而不是实例生成的。