Объясните насчет переопределения Equals(object)
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 17.05.18 18:03
Оценка:
Копаюсь в чужом коде

Вижу:

class TMy
{
 //....

 public override bool Equals(object obj)
 {
  if (ReferenceEquals(null, obj))
   return false;

  if (ReferenceEquals(this, obj))
   return true;

  return obj.GetType() == GetType() && Equals((TMy)obj);
 }

 public override int GetHashCode()
 {
  unchecked
  {
   //BLA-BLA-BLA
   return hashCode;
  }
};//class TMy


Объясните, плиз — зачем здесь влепили Equals(object)?

По-моему по умолчанию он делает ровно тоже самое. Не?

У меня из башки уже выветрились все эти нюансы.

Вроде было, что если переопределяешь GetHashCode, то нужно переопределить Equals.

Я попробовал закомментрировать этот Equals — все собралось (VS2017, .FW4.6.2)
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: Объясните насчет переопределения Equals(object)
От: StatujaLeha на правах ИМХО
Дата: 17.05.18 19:10
Оценка: 6 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>По-моему по умолчанию он делает ровно тоже самое. Не?


Неа.
https://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

If the current instance is a reference type, the Equals(Object) method tests for reference equality, and a call to the Equals(Object) method is equivalent to a call to the ReferenceEquals method. Reference equality means that the object variables that are compared refer to the same object.


Попробуй вот этот кода запустить.
    class MyClass: IEquatable<MyClass>
    {
        public int a = 1;

        public bool Equals(MyClass other)
        {
            Console.WriteLine("Typed Equals is called");
            return this.a.Equals(other.a);
        }
    }

    public partial class Program
    {
        public static void Main(string[] args)
        {
            object a = new MyClass();
            object b = new MyClass();

            Console.WriteLine(a.Equals(b)); // Типизированный Equals не вызовется.
            Console.WriteLine(((MyClass)a).Equals((MyClass)b));
        }
    }


Вывод:

False
Typed Equals is called
True

Re: Объясните насчет переопределения Equals(object)
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.05.18 09:49
Оценка: 6 (1)
Здравствуйте, Коваленко Дмитрий, Вы писали:


КД>
КД>class TMy
КД>{
КД> //....

КД> public override bool Equals(object obj)
КД> {
КД>  if (ReferenceEquals(null, obj))
КД>   return false;

КД>  if (ReferenceEquals(this, obj))
КД>   return true;

КД>  return obj.GetType() == GetType() && Equals((TMy)obj);
КД> }

КД> public override int GetHashCode()
КД> {
КД>  unchecked
КД>  {
КД>   //BLA-BLA-BLA
КД>   return hashCode;
КД>  }
КД>};//class TMy
КД>


КД>Объясните, плиз — зачем здесь влепили Equals(object)?


КД>По-моему по умолчанию он делает ровно тоже самое. Не?

Нет. По умолчанию, базовый Equals не вызывает типизированный Equals (см. выделенную часть).
По идее, вся соль должна быть в ней — если рядом нет public bool Equals(TMy other), то этот код просто некорректен (сваливается в бесконечную рекурсию при вызове на двух несовпадающих ссылках на TMy).
А если есть, то в нём, скорее всего, описана структурная эквивалентность (вроде this.x == other.x), которая по умолчанию для reference-типов не работает.

КД>Вроде было, что если переопределяешь GetHashCode, то нужно переопределить Equals.

Вообще-то — наоборот. Хеш-коды должны совпадать с классами эквивалентности, то есть у двух объектов, для которых возвращаются разные хеш-коды, Equals обязан возвращать false. Иначе ускоренные сравнения будут врать.
По умолчанию для объектов референс-типов в их класс эквивалентности входит только сам этот объект.
Когда мы перегружаем Equals, то, как правило, расширяем класс эквивалентности; дефолтный хеш-код при таком Equals становится неверным, т.к. одинаковые с т.з. Equals объекты возвращают разные хеш-коды.
Вот и приходится чинить GetHashCode для классов с перегруженными Equals.
В обратную сторону этого ограничения (почти) нет: я могу перегрузить GetHashCode моего класса в return 0; и никакая функциональность не пострадает (только производительность).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.