Копаюсь в чужом коде
Вижу:
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)
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>По-моему по умолчанию он делает ровно тоже самое. Не?
Неа.
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
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>КД>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; и никакая функциональность не пострадает (только производительность).