Страницы

Поиск по вопросам

вторник, 9 октября 2018 г.

Методы сравнения ссылочных классов в .Net

Ранее считал, что переопределять Equals для своих классов можно и нужно. Но натолкнулся на иную информацию, что переопределение может привести к проблемам с некоторыми коллекциями.
Когда следует переопределять object.Equals() для своих классов? Неужели, если хочется сравнить на эквивалентность согласно сущности два объекта своих классов, нужно создавать отдельный метод? А как быть со сторонними классами? Получается они не поставляют средств сравнения на эквивалентность сущностей?
Что я понимаю под эквивалентностью сущностей. Допустим есть класс
public class Country { public Country (string name) { this.name = name; } private readonly string name; public string Name { get {return name;}} }
public void Main() { var c1 = new Country("Россия"); var c2 = new Country("Россия"); }
так вот c1 и с2 для меня эквивалентны, т.к. не может быть двух стран в моём мире, с одинаковым названием. Просто так получилось, что мы создали два экземпляра, но они идентичны по своей сути..


Ответ

Как известно, .NET по умолчанию сравнивает объекты ссылочных типов по ссылкам, а объекты значимых типов -- побитово (читай, по значению).
К чему это приводит в вашем примере? К тому, что c1 и c2 считаются неравными. С т.з. бизнес-логики вы правильно заметили, что они равны, однако среда ничего не знает о бизнес-логике.
Отсюда выводы:
Метод Equals() надо переопределять там, где требуется, чтобы объекты считались равными по какому-то определенному правилу. В частности, это нужно, когда вы используете объекты типа в качестве ключей словаря, элементов хэш-сета, а также в качестве элемента какой-либо коллекции и вызываете метод Contains(). Также стоит заметить, что в пару к Equals() нужно переопределять и метод GetHashCode() Да, нужно. Потому что правила равенства двух объектов одного типа -- это, грубо говоря, бизнес-правила, то, что относится к вашему приложению. Среда исполнения о них ничего не знает, но о них знаете вы как разработчик. Для кастомного сравнения экземпляров сторонних классов используется интерфейс IEqualityComparer и его реализации. В BCL включены некоторые готовые реализации (например, для сравнения строк без учета регистра). В большинстве случаев вам потребуется создавать свой компаратор.

Комментариев нет:

Отправить комментарий