What is the purpose of the Gethashcode() method?

Asked

Viewed 2,912 times

9

I’m using Resharper to automate the method override Equals and the operator ==. One of the methods the tool has 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 configured for the version 4.5.1 of .NET Framework).

Complete code of the class:

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

2 answers

8


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

You need a code that avoids too many collisions, so you need to use a number that is easy to generate different codes. A prime number is quite obvious, it cannot be too low, nor too large to have a good distribution.

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

The algorithm must consider all members that form the identity of the object and it is frequent to use the hash code of the members to form the whole object code.

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

See about the 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) => Equals(left, right);

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

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

Jon Skeet’s response with an example.

5

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

The same code of hash can be generated for two different objects, although it rarely occurs. Mr Maniero’s reply explains the use of 397 in general in order to avoid frequent collisions.

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

  • 1

    I think at the very least there are some inaccuracies in this, not to mention that it’s wrong.

  • Could you clarify these inaccuracies?

  • I am willing to correct any information... I have put the information I believe to be correct in my answer. If you have any information or improvement for future understanding please indicate so that we can contribute together.

  • @Marcellalves O método GetHashCode é utilizado para comparação entre valores de objetos, not for this, in my answer has to what is and details on the link. método Equals herdado e não sobrescrito da classe Object que compara entidades por referência (compara o endereço de memória de dois objetos), is also wrong, the Equals() compare what he wants to buy, may even be the reference, but usually it is not. provavelmente uma sequencia interna do Resharper incrementada para cada novo GetHashCode gerado has nothing to do with Resharper.

  • o resultado desta multiplicação potencialmente poderia exceder limites de memória ñ is well this. Todo método Equals que tenha por intenção comparar valores e não referências a locais de memória deve comparar o retorno de GetHashCode para os objetos de entrada this insists on the error.

  • Thanks for the corrections, @bigown. I changed the acceptance of the answer, but I still think it valid Bruno edit your answer with the corrections you put.

  • Bigown, the comment on the Equals method of the Object class is incorrect. I am sure that this method if no override is made compares memory addresses, which may or may not be true if there is override. Also according to the same comment his explanation of prime numbers is more explanatory than my suggestion (I put as probably because I am not sure of this part).

  • About the comment regarding the memory overflow... yes this is the usability of the keyword "unchecked" which by the way your answer ignores this part of the question. I ask you to suggest a better explanation for using this keyword that allows anyone who reads your answer to understand the code instead of simply allowing you to copy it without understanding.

  • 1

    @Brunodossantosbermann is true, I didn’t notice the nay superscript, I’m sorry for that flaw, the rest is really wrong. There is no memory overflow, there may be value arithmetic overflow and the signal bit affected. I put in the answer. Then I can improve something, on link has more information about the calculation in Jon Skeet’s answer.

  • Anyway thank you, later I will make the adjustments in response as proposed.

Show 5 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.