为什么两个委托实例返回相同的哈希码?

本文关键字:返回 哈希码 实例 两个 为什么 | 更新日期: 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方法,它可能会返回相同的值。我怀疑这是因为它是从定义而不是实例生成的。