10

My search for a helper to correctly combine constituent hashcodes for GetHashCode() seemed to garner some hostility. I got the impression from the comments that some C# developers don't think you should override GetHashCode() often - certainly some commenters seemed to think that a library for helping get the behaviour right would be useless. Such functionality was considered useful enough in Java for the Java community to ask for it to be added to the JDK, and it's now in JDK 7.

Is there some fundamental reason that in C# you don't need to - or should definitely not - override GetHashCode() (and correspondingly, Equals()) as often as in Java? I find myself doing this often with Java, for example whenever I create a type that I know I want to keep in a HashSet or use as a key in a HashMap (equivalently, .net Dictionary).

Community
  • 1
  • 1
bacar
  • 9,761
  • 11
  • 55
  • 75
  • 1
    You should override GetHashCode() when creating types that represent values. – SLaks Aug 05 '13 at 20:03
  • @Slaks such as `int`, `double` and `Point`? – Federico Berasategui Aug 05 '13 at 20:03
  • Related: http://stackoverflow.com/questions/2907372/why-does-c-sharp-not-implement-gethashcode-for-collections – assylias Aug 05 '13 at 20:04
  • @bacar the question is why is your code (seemingly) so fond of Dictionaries to begin with. – Federico Berasategui Aug 05 '13 at 20:04
  • @SLaks my guess was that .net's value types provide a decent GetHashCode for you and there should be little need to provide your own, but I thought I'd see if the community has a more comprehensive answer. – bacar Aug 05 '13 at 20:05
  • I would love to hear #Jon's and #Eric's thoughts on this. – Federico Berasategui Aug 05 '13 at 20:06
  • @HighCore: I've added mine to the original question. I'm not going to add an answer here, as it's not really an ideal question for SO at the moment - it's not really specific enough, to be honest. – Jon Skeet Aug 05 '13 at 20:09
  • 3
    @HighCore: `Dictionary<,>` is an incredibly useful type... not that it's the only use for overriding Equals/GetHashCode. It's often useful to be able to create a set of distinct elements, too. I don't think there's any reason to suggest that the OP *overuses* dictionaries, as you seem to be implying. – Jon Skeet Aug 05 '13 at 20:11
  • 3
    Deleted my answer, but two thoughts: in .NET, the cases where you *need* to implement this is the small % of a small % - so the "why not?" is "because you don't need to". But it seems possible it could also relate quite tightly to mutability / immutability; .NET objects are usually mutable, and custom GetHashCode implementations on a mutable type can be dangerous – Marc Gravell Aug 05 '13 at 20:19
  • Do you need two identical objects to be equal? In addition I always override hash if the object has a natural static key. – paparazzo Aug 05 '13 at 20:53
  • 1
    @bacar: Actually, value types provide a very poor implementation of `GetHashCode()`. See http://msdn.microsoft.com/en-us/library/ms182276.aspx – SLaks Aug 05 '13 at 21:43

3 Answers3

1

C# has built-in value types which provide value equality, whereas Java does not. So writing your own hashcode in Java may be a necessity, whereas doing it in C# may be a premature optimisation.

It's common to write a type to use as a composite key to use in a Dictionary/HashMap. Often on such types you need value equality (equivalence) as opposed to reference equality(identity), for example:

IDictionary<Person, IList<Movie> > moviesByActor; // e.g. initialised from DB
// elsewhere...
Person p = new Person("Chuck", "Norris");
IList<Movie> chuckNorrisMovies = moviesByActor[p];

Here, if I need to create a new instance of Person to do the lookup, I need Person to implement value equality otherwise it won't match existing entries in the Dictionary as they have a different identity.

To get value equality, you need an overridden Equals() and GetHashCode(), in both languages.

C#'s structs (value types) implement value equality for you (albeit a potentially inefficient one), and provide a consistent implementation of GetHashCode. This may suffice for many people's needs and they won't go further to implement their own improved version unless performance problems dictate otherwise.

Java has no such built-in language feature. If you want to create a type with value equality semantics to use as a composite key, you must implement equals() and correspondingly hashCode() yourself. (There are third-party helpers and libraries to help you do this, but nothing built into the language itself).

I've described C# value types as 'potentially inefficient' for use in a Dictionary because:

Community
  • 1
  • 1
bacar
  • 9,761
  • 11
  • 55
  • 75
0

If your object represents a value or type, then you SHOULD override the GetHashCode() along with Equals. I never override hash codes for control classes, like "App". Though I see no reason why even overriding GetHashCode() in those circumstances would be a problem as they will never be put in a position to interfere with collection indexing or comparisons.

Example:

public class ePoint : eViewModel, IEquatable<ePoint>
{
    public double X;

    public double Y;

    // Methods

    #region IEquatable Overrides

    public override bool Equals(object obj)
    {
        if (Object.ReferenceEquals(obj, null)) { return false; }

        if (Object.ReferenceEquals(this, obj)) { return true; }

        if (!(obj is ePoint)) { return false; }

        return Equals((ePoint)obj);
    }

    public bool Equals(ePoint other)
    {
        return X == other.X && Y == other.Y;
    }

    public override int GetHashCode()
    {
        return (int)Math.Pow(X,Y);
    }

    #endregion
  • 1
    Thanks. This is just as true of Java as of C#. It doesn't explain if there is a particular reason that this is required less often in C# vs Java. – bacar Aug 05 '13 at 20:14
  • If its the same, then in what other circumstances does java require it? – KindaFearless Aug 05 '13 at 20:19
0

I wrote a helper class to implement GetHashCode(), Equals(), and CompareTo() using value semantics from an array of properties.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964