4

Господа, не могу понять каким образом переопределять метод GetHashCode(). Ведь, насколько я понял, хешкод берется из скрытой переменной в объекте, к которой нет доступа. Тогда как мне его переопределить ?? Если не затруднит, то хотелось бы увидеть какой-то элементарный пример. И еще не пойму, почему разные хешкоды в коде

using System;
class a
{
    public int x;
    public a(int y)
    {
        x = y;
    }
}
class b
{
    static void Main()
    {
        Console.WriteLine(new a(5).GetHashCode() + " " + new a(5).GetHashCode());
    }
}

Ведь тут написано https://msdn.microsoft.com/ru-ru/library/system.object.gethashcode(v=vs.110).aspx

Для двух одинаковых объектов возвращенные хэш-коды равны

9
  • 2
    в книге Блоха "Java. Эффективное программирование" есть пару глав по этому вопросу, доступно расписано, для C# принцип подходит. Для двух одинаковых объектов возвращенные хэш-коды равны, но в Вашем примере они не одинаковые, проверьте Console.WriteLine((new a(5)) == (new a(5))); И кстати, приведенная Вами цитата не соответствует английской версии, в которой сказано, что реализация метода GetHashCode() по умолчанию не гарантирует, что для разных объектов будет разный хешкод 25 фев 2015 в 12:55
  • 1
    @polyakov_s еще раз обращаю ваше внимание - пожалуйста давайте своим классам и методам адекватные имена, а не бессмысленные а, b или с. Если хотите помощи, то уважайте и усилия тех людей, чьей помощи вы просите.
    – DreamChild
    25 фев 2015 в 12:57
  • 2
    Не сочтите за наглость, однако я не пойму, я написал примитивный учебный код, в котором классы не имеют никакого функционального смысла и, как следствие, я не могу даже представить какое им имя дать. На мой взгляд, есть стандартные имена численных переменных которые не имеют смысловой нагрузки например X Y. Так же есть имена классов, которые совершенно бестолковые с точки зрения функциональности и поэтому я даю им имена A B ... Конечно, есть люди, называющие свои класы в стиле "sfdkjf" - я тут с вами согласен, но что плохого в А и Б в 3 х строчках кода. Простите уж. 25 фев 2015 в 13:15
  • 1
    @polyakov_s в первую очередь написание осмысленного и читаемого кода в ваших же интересах. Если вам доведется работать программистом, то эту привычку из вас будут выбивать, хотелось бы вам этого или нет. Касательно вашего примера скажу, что, скажем, когда я смотрю на код и вижу в нем подобные идентификаторы, то автоматически думаю, что а - это имя какой-то локальной переменной, причем скорее всего незначительной, и нужно определенное (пусть и небольшое) усилие, чтобы проанализировать код и понять, что a - это имя класса. Тем самым в сбиваете с толку человека, который хотел бы вам помочь.
    – DreamChild
    25 фев 2015 в 13:21
  • 3
    @DreamChild Называть классы Foo, Bar, Baz, Qux — совершенно нормальная практика в примерах. Осмысленные имена ничего не добавят. Всему своё место. Хотя b.Main — это, конечно, избыточная экономия на буквах.
    – Kyubey
    25 фев 2015 в 13:35

1 ответ 1

6

Ведь, насколько я понял, хешкод берется из скрытой переменной в объекте, к которой нет доступа.

Так ведь и метод вы переопределяете в своем же классе :). Что-то типа:

class a
{
    public int x;

    public a(int y)
    {
        x = y;
    }

    public override int GetHashCode()
    {
        return x;
    }
}

Есть несколько правил для переопределения GetHashCode(), основные:

  1. Используемая функция должна давать хорошее распределение. Это, строго говоря, зависит от данных, однако часто хорошо подходит подобная функция:
    public override int GetHashCode()
    {
        int hashcode = field1.GetHashCode();
        hashcode = 31 * hashcode + field2.GetHashCode();
        hashcode = 31 * hashcode + field3.GetHashCode();
        // и т.д. для остальный полей
        return hashcode;
    }
  1. Эта функция должна быть быстрой.

  2. GetHashCode() не должен выбрасывать исключения.

  3. В идеале GetHashCode() не должен меняться в течение жизни объекта, т.е. полагаться только на неизменяемые члены класса. На практике этим часто пренебрегают, пока не стрельнет.


Так же не забудьте, что Equals() и GetHashCode() всегда должны идти в паре: переопределили один метод, переопределяйте и другой. И если два объекта равны, то у них должен быть одинаковый хэшкод. Обратное необязательно верно (хэш-функция может вернуть одинаковое дначение для разных объектов).


Что почитать (на английском):

Про правильное переопределение GetHashCode()

Про хэш-функции

Ваш ответ

By clicking “Отправить ответ”, you agree to our terms of service and acknowledge you have read our privacy policy.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками или задайте свой вопрос.