Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I HAVE to override GetHashCode and Equals in new Classes?

Tags:

.net

Okay, so if I override Equals, I need to override GetHashCode and vice versa.

But I just wonder: Should I always override these two in any class? Especially if I know that I will use them in a Dictionary or similar collections? While this is fairly straight forward, it's still an extra work for every class.

Is the System.Object implementation bad enough to worry about this?

Edit: Can you detail a bit more what is Value and Reference equality? So if I have two strings (s1 and s2) that are both "test", they are value equal, but since they are two different strings, they are not reference-equal? Ok, for strings it's a no-brainer, but what are the common situations where you would want Reference or Value Equality?

like image 911
Michael Stum Avatar asked Dec 23 '22 12:12

Michael Stum


1 Answers

As far as I'm aware you only need to override them if you need value equality semantics. The System.Object implementation isn't 'bad', it just only does a reference check (which is all an implementation at that level can do).

In short: If you need some sort of value based equality (equality based on properties of the class), then yes, override away. Otherwise, it should be more than fine already.

EDIT: You only need to override them in the case above. If you override one, you do need to override both for the obvious reasons (they need to be consistent, etc). You can override them on every class for other reasons noted in other answers (like performance in algorithms that use the hash value, ie. Dictionary keys, etc), but you don't need to, the default System.Object implementation will work correctly.

EDIT 2: More information requested, so here goes. Consider the following pseudo-class:

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.
    }
}

As it stands, the following code, might seem intuitive:

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!");
}

But it will only print out:

2: Success

Why? foo and bar are two seperate instances of the class, and have separate references. A reference is like a pointer in C/C++. foo and baz are the same reference because one was assigned from the other. They all have the same value though, the user called "me". A sample implementation of a value based .Equals implementation might be:

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;
    }
}

See how it checks against part of the class's properties to determine equality? That's value equality at work. Reference equality would just be a simple this == b check.

like image 72
Matthew Scharley Avatar answered May 18 '23 15:05

Matthew Scharley