What is the purpose of the GetHashCode () method?

5

I am using Resharper to automate overwriting of the Equals method and the == operator. One of the methods the tool overwritten is GetHashCode :

public override int GetHashCode()
{
    unchecked
    {
        return (Id.GetHashCode() * 397) ^ (Name != null ? Name.GetHashCode() : 0);
     }
}

What is the function of this method and what is its role in comparing objects in the .NET Framework ? What is the function of the reserved word unchecked ? Why multiply the value of HashCode of property Id by 397? (The project is set to .NET Framework version 4.5.1 ).

Full class code:

public class Class1 : IEquatable<Class1>
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public bool Equals(Class1 other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Id.Equals(other.Id) && string.Equals(Name, other.Name);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((Class1) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (Id.GetHashCode() * 397) ^ (Name != null ? Name.GetHashCode() : 0);
        }
    }

    public static bool operator ==(Class1 left, Class1 right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Class1 left, Class1 right)
    {
        return !Equals(left, right);
    }
}
    
asked by anonymous 20.03.2017 / 14:14

2 answers

6

Most of the question has already been answered in What is Hashcode and what is its purpose? . It says that it is mainly for use in hash tables where the most prominent type is Dictionary .

A code that avoids many collisions is needed, so you must use a number that is easy to generate different codes. A prime number is pretty obvious, it can not be too low, nor too large to have a good distribution.

There are controversies of the ideal number or if just a simple form using multiplication and xor are sufficient. On the other hand, if you make a very complicated formula, besides being able to slow down it may end up having the opposite effect.

The algorithm must consider all members that form the identity of the object, and often use the hash code of the members to form the whole object code.

Some people say that it was a mistake to require every object to be hashable , and they think there should be an interface that allows this where it makes sense.

See about unchecked .

using System;
using static System.Console;
using System.Collections.Generic;

public class Program {
    public static void Main() {
        var dict = new Dictionary<Class1, int> { { new Class1 { Id = new Guid(), Name = "João" }, 0 }};
        foreach (var item in dict) {
            WriteLine(item.Key.Name);
        }
    }
}

public class Class1 : IEquatable<Class1> {
    public Guid Id { get; set; }
    public string Name { get; set; }

    public bool Equals(Class1 other) {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Id.Equals(other.Id) && string.Equals(Name, other.Name);
    }

    public override bool Equals(object obj) {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((Class1) obj);
    }

    public override int GetHashCode() {
        unchecked {
            int hash = (int) 2166136261;
            hash = (hash * 16777619) ^ Id.GetHashCode();
            return hash = (hash * 16777619) ^ (Name != null ? Name.GetHashCode() : 0);
        }
    }

    public static bool operator ==(Class1 left, Class1 right) {
        return Equals(left, right);
    }

    public static bool operator !=(Class1 left, Class1 right) {
        return !Equals(left, right);
    }
}

See running on .NET Fiddle . And at Coding Ground . Also put it on GitHub for future reference .

Jon Skeet's Answer with an example .

    
20.03.2017 / 14:22
4

The GetHashCode method is used to compare object values, unlike the inherited and non-overridden Equals method of the Object class that compares entities by reference (compares the memory address of two objects).

The same hash code can be generated for two distinct objects, although it rarely occurs. The answer from fellow bigown explains the use of the number 397 generically in order to avoid frequent collisions.

Using the unchecked keyword ignores any exception generated as a result of arithmetic overflow (the result of this multiplication could potentially exceed memory limits according to the type resulting from the operation).

I hope I have been useful.

    
20.03.2017 / 14:25