Должен ли .GetHashCode() возвращать одно и то же значение для двух объектов, имеющих разные ссылки в памяти?

Мне нужно переопределить метод Equals() для одного из моих типов, но, похоже, мне также нужно переопределить метод GetHashCode().

Я не уверена:

Если у меня есть тип Animal и если у меня есть 2 экземпляра Animal, которые в основном являются одними и теми же (равными) Cats; подобно:

Animal cat_01 = new Animal("Kitty", "Pink");
Animal cat_02 = new Animal("Kitty", "Pink");

Должен ли я реализовать GetHashedCode(), чтобы вернуть одно и то же значение как для cas_01, так и для cat_02, даже если они представляют разные ссылки в памяти?

Так ли должен работать GetHashCode()?

Спасибо


person pencilCake    schedule 05.09.2011    source источник
comment
По сути, ваш класс Animal, вероятно, должен не переопределять Equals, GetHashCode или ==. Если вы это сделаете, то также спроектируйте его как неизменяемый. Также см. ответ MattDavey.   -  person Henk Holterman    schedule 05.09.2011


Ответы (3)


MSDN сообщает:

Если два объекта сравниваются как равные, метод GetHashCode для каждого объекта должен возвращать одно и то же значение.

Так что да, GetHashCode должен возвращать одно и то же значение для обоих экземпляров.

Вы по-прежнему можете использовать Object.ReferenceEquals, если хотите увидеть, ссылаются ли они на один и тот же объект.

person Botz3000    schedule 05.09.2011
comment
К сведению всех, кто столкнется с этим вопросом в будущем - это не правильный ответ во всех обстоятельствах. Уделите некоторое внимание с точки зрения объектно-ориентированного программирования, когда ваши сущности следует считать равными, а когда нет. Считать объекты всегда равными, когда они имеют схожие свойства, часто является ошибкой. - person MattDavey; 05.09.2011
comment
Мой ответ просто отвечает на основной вопрос: должен ли GetHashCode возвращать одно и то же значение для двух объектов, где Equals возвращает true? Разумеется, имеет ли смысл переопределение equals в этом случае. - person Botz3000; 05.09.2011

Я бы не согласился с другими ответами. Животное в этом примере не является объектом значения, вполне возможно, что две кошки могут иметь одинаковое имя и цвет и быть совершенно разными объектами. Логически вы говорите, что «у этого кота и у того кота одно и то же имя и один и тот же цвет, следовательно, это один и тот же кот» — что не обязательно верно.

Я бы посоветовал вам оставить Animal.Equals для реализации по умолчанию и создать отдельную реализацию IEqualityComparer, которая возвращает true, если животные имеют одинаковое имя/цвет.

public class AnimalNameColorComparer : IEqualityComparer<Animal>
{
    public bool Equals(Animal a, Animal b)
    {
        return a.Name == b.Name &&
               a.Color == b.Color
    }

    public int GetHashCode(Animal a)
    {
        return a.Name.GetHashCode() ^ a.Color.GetHashCode();
    }
}

Постарайтесь помнить, что существует много разных способов сравнить кошку, и одного единственного метода "Равно" недостаточно :)

// Create two black cats called fluffy...
var cat1 = new Cat("Fluffy", "Black");
var cat2 = new Cat("Fluffy", "Black");

cat1.Equals(cat2) == false; // they are not the same cat!

var comparer = new AnimalNameColorComparer();

comparer.Equals(cat1, cat2) == true; // But they do have the same name & colour...
person MattDavey    schedule 05.09.2011
comment
Этот вопрос конкретно касается реализации GetHashCode, которая является особым требованием для ключей, используемых при поиске типа словаря. Равенство считается после генерации хэш-кода, если есть коллизии. - person Tim Lloyd; 05.09.2011
comment
если вы ссылаетесь на пользователя, не являющегося автором, в комментарии, вы должны указать его @username, иначе он не будет уведомлен. - person Tim Lloyd; 05.09.2011
comment
+1 за то, что не ответил на вопрос, но указал на ошибку дизайна, которая его вызвала. - person Henk Holterman; 05.09.2011
comment
Вернемся к теме: переопределяя GetHashCode, вы не можете иметь двух кошек с одинаковым именем и цветом в словаре, действительно ли это желаемое поведение программы? Оставить GetHashCode и Equals с их реализацией по умолчанию было бы правильно в этом случае. - person MattDavey; 05.09.2011
comment
@Matt Да, в словаре могут быть две кошки с одинаковым именем и цветом, это ключи, под которыми они хранятся, и они не могут быть одинаковыми. GetHashCode вызывается для ключа. - person Tim Lloyd; 05.09.2011
comment
Это хороший момент, НО я думаю, что мы можем быть достаточно уверены, что класс фактического спрашивающего не является Animal, поэтому (абсолютно верное) утверждение о том, что животные реального мира не однозначно идентифицируются по их имени и цвету, не имеет значения. не обязательно применять. Обратите внимание, что текст вопроса включает в себя те, которые в основном совпадают, что предполагает, что для фактического класса равенство этих двух членов действительно подразумевает равенство идентичности. - person AakashM; 05.09.2011

В зависимости от дизайна модели, если это объект-значение (неизменяемый), то gethashcode должен возвращать хешированное значение всех полей, но, с другой стороны, если это объект домена, то он должен иметь идентификатор, и этот идентификатор должен использоваться для сравнения и гетхэшкода (два человека с одинаковым именем и возрастом не совпадают, если у вас есть две кошки с одинаковым именем, это не значит, что это одна и та же кошка!).

проверьте: http://moh-abed.com/2011/07/13/entities-and-value-objects/

person Mohamed Abed    schedule 05.09.2011