采取以下措施:
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)
进行查找)。
更新
问题是为什么。 IOW谁做出这样一个(愚蠢的)决定?
更好的哈希码实现应该是:
return Method ^ Target == null ? 0 : Target.GetHashcode();
// where Method is IntPtr
答案 0 :(得分:9)
轻松!由于这里是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之类的工具,我们可以看到代码,看起来默认的实现就像上面看到的 strange 一样。
此处的类型值为Action
。因此,上面的结果是正确。
答案 1 :(得分:3)
我首次尝试更好地实施:
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会返回最后一个元素委托的值)。
但我不确定它是否在所有极端情况下都符合合同。
看起来质量需要目标的参考平等。
答案 2 :(得分:1)
这闻起来像这个帖子中提到的一些案例,也许它会给你一些关于这种行为的指示。否则,你可以在那里登录: - )
What's the strangest corner case you've seen in C# or .NET?
Rgds GJ
答案 3 :(得分:1)
来自MSDN:
默认实现 GetHashCode不保证 独特性或一致性;因此, 它不能用作唯一对象 用于散列目的的标识符。 派生类必须覆盖 带有实现的GetHashCode 返回唯一的哈希码。对于 最好的结果,哈希码必须是 基于实例的值 字段或属性,而不是静态的 田地或财产。
因此,如果您没有覆盖GetHashCode方法,它可能会返回相同的内容。我怀疑这是因为它是从定义生成的,而不是实例。