Dictionary<T>如何处理不实现Equals和GetHashCode方法的键对象?

4
如果我将一个不实现Equals和GetHashCode的键对象放入一个字典中,那么字典的ContainsKey如何工作?它会检查引用是否相等吗?
谢谢。
2个回答

6
基础的 Object 类实现了 EqualsGetHashCode。所有类默认都继承自 Object。字典将只使用这些实现。
Equals 的默认实现测试对象引用,在大多数情况下对于您的字典可能是可以的。
GetHashCode 的基本实现相当幼稚,事实上,即使文档也说明:
默认的 GetHashCode 方法的实现不能保证为不同的对象返回唯一的返回值。
因此,如果您打算将一个对象用作字典或哈希表键,则建议自己重写它。
关于这个问题,记住 GetHashCode 对于字典的实现并不是非常关键。哈希码允许冲突,这也是它的意义所在。哈希码只是用来帮助定位对象的,最终使用的是相等性测试来检查对象是否正确。假设每个对象都返回哈希码 1,它们都会被放在字典中的同一个位置上,可能是一些相当随机的顺序(也许是插入顺序),然后就会回退到使用 Equals 来验证对象的身份。这样做效率不高,但可以正常工作。

因此,如果你想要更高的效率,应该考虑重写 GetHashCode,但如果只是一个小型字典且效率不是很重要,那么只需使用默认值即可。

[所有通常的注意事项仍然适用。最好不要为可变对象重写 GetHashCode,并确保对于返回 true 的 Equals() 对象返回相同的哈希码。]


@DayOne,这个位是如何工作的?我添加了一些更多的信息。微软没有提供关于默认的GetHashCode如何工作的文档,并且他们还说它可能会在不同版本之间发生变化。 - Simon P Stevens
3
GetHashCode 方法对于不同的对象返回的哈希值不唯一并不妨碍在字典中使用它。最常见的键类型可能是 string,但很明显没有一种 GetHashCode 函数可以将每个可能的字符串值映射到唯一的 uint 值上。 - Daniel Earwicker
@Daniel。我刚刚添加了非常相似的东西。好评论。 - Simon P Stevens

0

它使用Object.GetHashCode实现,但请注意,此哈希码不是对象标识:

GetHashCode方法的默认实现不能保证为不同对象返回唯一的返回值。此外,.NET Framework不保证GetHashCode方法的默认实现,并且它返回的值将在.NET Framework的不同版本之间相同。因此,不能将此方法的默认实现用作散列目的的唯一对象标识符。

如果您想让字典基于引用相等运行,则可以在构建字典时使用以下比较器:

class ReferenceComparer<T> : IEqualityComparer<T>
{
    public bool Equals(T x, T y)
    {
        return object.ReferenceEquals(x, y);
    }

    public int GetHashCode(T obj)
    {
        return obj.GetHashCode();
    }
}

这没有任何价值,System.Object已经以这种方式运作。如果没有类约束,它在值类型上的表现非常糟糕。 - Hans Passant
此外,在实现自己的 GetHashCode() 函数时,您应该小心。如果它基于对象内容生成哈希码,并且这些内容是可变的,那么您可能会失去字典元素。这就是为什么您应该真正喜欢使用不可变类型作为字典键的另一个卓越建议。这是 Bill Wagners 的《Effective C#》中的另一条优秀建议 - 第7项:首选不可变原子值类型。 - Mark Booth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接