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

Возможный дубликат:
Что такое "Лучшая практика" для сравнения двух экземпляров ссылочного типа?

У меня есть этот пользовательский класс для моего приложения. Есть два экземпляра (A и B) этого класса, которые я пытаюсь сравнить. Однако у меня проблемы; Я реализую IEquatable<T> интерфейс, чтобы сделать это сравнение, используя переопределенный Equals методы.

Equals методы вызывает ReferenceEquals функция, которая плохо себя ведет.

Вот тестовые случаи:

Случай 1: A и B являются разными экземплярами и содержат разные данные. ReferenceEquals говорит: они разные (что правильно!)

Случай 2: A и B - разные экземпляры, но B был создан с использованием значений переменных A (т.е. и A, и B содержат точно такие же данные!) .. ReferenceEquals говорит: они разные (что не так!)

Случай 3: A и B являются одинаковыми экземплярами (т.е. A передается дважды, например Equals (A, A)) ReferenceEquals говорит: они одинаковы (что правильно!)

Так как же получить правильный результат в случае 2?

Класс в котором IEquatable<T> реализовано:

namespace DBtestApp1
{
    class QuantityBasedDiscount : IEquatable<QuantityBasedDiscount>
    {
        public string pType { get; set; }
        public string pSubType { get; set; }
        public DataTable quantityDiscountsDT { get; set; }

        public QuantityBasedDiscount()
        {
            pType = "";
            pSubType = "";
            quantityDiscountsDT = new DataTable();
        }

        public QuantityBasedDiscount(string iProdType, string iProdSubType, DataTable iQuantitiesDT)
        {
            pType = iProdType;
            pSubType = iProdSubType;
            quantityDiscountsDT = iQuantitiesDT;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(Object obj)
        {

            var other = obj as QuantityBasedDiscount;
            if (other == null) return false;

            return Equals(other);
        }

        public bool Equals(QuantityBasedDiscount other)
        {
            if (other == null)
            {
                return false;
            }

            if (ReferenceEquals(this, other))
            {
                return true;
            }

            return false;
        }
    }
}

Код, который вызывает Equals метод (настроен для случая 2 здесь):

private bool AnyUnsavedChanges()
{
    QuantityBasedDiscount copyB = new QuantityBasedDiscount(copyA.pType, copyA.pSubType, copyA.quantityDiscountsDT);

    if (copyA.Equals(copyB))
    {
         return false; //They are the same!
    }
    else
    {
         return true; //They are NOT the same!
    }

}

Так в чем же проблема в этом коде?

2 ответа

Хотя это и не точный дубликат, у вас есть все ответы здесь: Что такое "Лучшая практика" для сравнения двух экземпляров ссылочного типа?, Получить фрагмент при условии ответа Конрада из этой темы, чтобы никогда не ошибиться.


Короче говоря, вы делаете это неправильно. Вы не сравниваете фактические значения в вашем общем Equals метод. Кроме того, не безопасно звонить == оператор внутри Equals методы. Сделай это так:

public override int GetHashCode()
{
    return pType.GetHashCode() ^ pSubType.GetHashCode() ^ quantityDiscountsDT.GetHashCode();
    //or something similar, but fast.
}

public bool Equals(QuantityBasedDiscount other)
{
   if (ReferenceEquals(null, other))
    {
        return false;
    }

    if (ReferenceEquals(this, other))
    {
        return true;
    }

    return pType == other.pType && pSubType == other.pSubType && 
           quantityDiscountsDT == other.quantityDiscountsDT;
}

Это может привести к противоречивым результатам, если изменить поле DataTable. Все зависит от того, как == Оператор реализован для DataTable. Чтобы иметь больше контроля над этим, вам придется получить свой собственный DataTable.

Кроме того, вы можете захотеть перегрузить == а также != оператор тоже. Для всего этого проверьте предоставленную ссылку.

Вы должны переопределить Equals и GetHashCode и, если вам нравится / нужен синтаксис, вам также необходимо перегрузить операторы '==' и '!='. В переопределении Equals вы можете сначала проверить, возвращает ли ReferenceEquals значение true, а если нет, то сравнить содержимое объектов.

Лично я предпочитаю избегать использования ReferenceEquals в таких случаях.

Другие вопросы по тегам