我需要在新类中重写GetHashCode和Equals吗?

4

好的,如果我重写Equals,我需要重写GetHashCode,反之亦然。

但我想知道:我是否应该在任何类中始终重写这两个方法?特别是如果我知道我将在字典或类似集合中使用它们?虽然这相对来说相当简单,但对于每个类来说仍然是额外的工作。

System.Object的实现是否糟糕到值得担心这个问题?

编辑:您能详细说明一下值相等和引用相等吗?所以如果我有两个字符串(s1和s2)都是“test”,它们是值相等的,但由于它们是两个不同的字符串,它们不是引用相等的?好的,对于字符串来说很简单,但什么情况下您希望有引用或值相等?

3个回答

6
据我所知,只有在需要值相等语义时才需要覆盖它们。System.Object实现并不“糟糕”,它只执行引用检查(这是该级别上的实现可以执行的所有操作)。
简而言之:如果您需要某种基于值的相等性(基于类属性的相等性),那么是的,可以覆盖它们。否则,已经足够好了。
编辑: 只有在上述情况下才需要覆盖它们。如果您覆盖其中一个,则由于明显的原因(它们需要一致等等),您需要同时覆盖两者。您可以出于其他答案中指出的其他原因(例如使用哈希值的算法(例如Dictionary键)的性能等)在每个类上覆盖它们,但不需要这样做,默认的System.Object实现将正常工作。
编辑2: 请求更多信息,请参考以下伪类:
public class User {
    private int _id;
    private string _username;
    public string Username { get {return _username;}};
    // [snip] Whatever other properties we might like to have.

    public User(string username) {
        // Initialise our user from a database, or whatever.
    }
}

当前的代码看起来很直观:

User foo = new User("me");
User bar = new User("me");
User baz = foo;

if (foo.Equals(bar)) {
    Console.WriteLine("1: Success!");
}
if (foo.Equals(baz)) {
    Console.WriteLine("2: Success!");
}

但是它只会打印出:

2:成功

为什么?foobar是该类的两个独立实例,并具有单独的引用。引用类似于C/C++中的指针。foo和baz是相同的引用,因为一个是从另一个分配的。它们所有的都相同,即用户称之为“me”。一个基于值的.Equals实现的示例可能是:

partial class User {
    public override bool Equals(object b) {
        if (b == null) return false;
        if (b.GetType() != this.GetType()) return false;

        // Now the heavy lifting
        User other = (User)b;
        if (other._id == this._id) return true;
        else return false;
    }
}

看到它如何检查类的一部分属性以确定相等性了吗?这就是值相等在起作用。引用相等只需简单的this == b检查。


3
两种方法应该是一致的。换句话说,如果两个对象相等,则每个对象应返回相同的哈希码。这在哈希集合中尤为重要。为了在哈希容器中找到与对象X匹配的对象,容器只会测试具有与X相同哈希码的项的相等性。

2
仅在需要值语义时使用。摘自MSDN
某些类型的对象需要测试值相等性而不是引用相等性。这种实现的Equals方法会在两个对象具有相同的值时返回true,即使它们不是同一实例。对象的值的定义取决于类型的实现者,但通常是对象实例变量中存储的部分或全部数据。例如,字符串的值基于字符串的字符;String类的Equals方法对于包含完全相同字符顺序的任何两个字符串实例都返回true。

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