@Take_it_and_do

Можно ли сравнивать через переопределенный GetHashCode() в C#?

Много где смотрел, пишут, что нужно переопределять Equals().

Я не могу смириться. По сути зачем, если можно в каждом классе переопределять GetHashCode() так:

public override int GetHashCode()
{
   return HashCode.Combine(field_1,field_N, base.GetHashCode());
}


Тогда в таком случае:

//Main
            TestA A = new TestA() { a = 35};
            TestA AB = new TestB() { a = 35, b = 332};
            TestB B = new TestB() { a = 35, b = 32};

            //Сравнение:
            //При выполнении Equals(): (A.Equals(AB))
            //  A и AB равны, что не cовсем
            //  AB и B равны, что неверно

            //При выполнении GetHashCode(): ((A.GetHashCode() == AB.GetHashCode())
            // A и AB не равны, что верно
            //  AB и B не равны, что верно


Необходимо мне сравнивать два класса, но передается только ссылка на их родителя. (У них одинаковый тип)

.          
            TestA AB_1 = new TestB() { a = 35, b = 332 };
            TestA AB_2 = new TestB() { a = 35, b = 3322 };

            ToCompare(AB_1, AB_2);

            void ToCompare(TestA A, TestA B)
            {
                Console.WriteLine(A.Equals(B)); //  True
                Console.WriteLine((A.GetHashCode() == B.GetHashCode()));    //False     
            }


Equals() ошибается (Для него нужно конкретно указывать тип наследников, которых нужно сравнить), а
GetHashCode() работает правильно.

Что тогда лучше? Могу ли я использовать хеш сравнение? Или может я ошибаюсь?

P.S.
public class TestA : IEquatable<TestA>
    {
        public int a;

        public override bool Equals(object obj)
        {
            return Equals(obj as TestA);
        }

        public bool Equals(TestA other)
            {
            return other != null &&
                   a == other.a;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(a);
        }

        public static bool operator ==(TestA left, TestA right)
        {
            return EqualityComparer<TestA>.Default.Equals(left, right);
        }

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


public class TestB : TestA, IEquatable<TestB>
    {
        public int b;

        public override bool Equals(object obj)
        {
            return Equals(obj as TestB);
        }

        public bool Equals(TestB other)
        {
            return other != null &&
                   base.Equals(other) &&
                   b == other.b;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(b, base.GetHashCode());
        }
    }
  • Вопрос задан
  • 149 просмотров
Решения вопроса 1
vabka
@vabka Куратор тега C#
Токсичный шарпист
GetHashCode - это не про сравнение, а про генерацию хэша для объекта.
Хэши могут пересекаться, тк количество хэшэй принципиально меньше количества уникальных объектов.
По тому, если тебе нужно ответить на вопрос "равен ли объект А объекту Б", то обязательно нужно проверить на Equals.
Чтобы при разных типах у тебя не было ложного совпадения - просто сравнивай ещё и тип в Equals (через GetType)

Если тебе нужно сравнить объекты по принципу больше/меньше/равно, то тут к тебе на помощь приходит интерфейс IComparable.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
freeExec
@freeExec
Участник OpenStreetMap
Одинаковый хешкод не гарантирует равенство объектов. А так, в своём коде вы вольны делать что угодно, хоть сравнивать только по одному полю.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы