Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Операции и приведения.docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
200.2 Кб
Скачать

Виртуальный метод Equals()

Реализация System.Object виртуальной версии Equals() также сравнивает ссылки. Однако, поскольку этот метод виртуальный, его можно переопределять в собственных классах, чтобы сравнивать объекты по значению. В частности, если вы намерены исполь­зовать экземпляры своего класса в качестве ключей словаря, то должны переопределить этот метод для сравнения значений. В противном случае, в зависимости от того, как вы пе­реопределите

Object.HashCode(), класс словаря, содержащий объекты, может либо вооб­ще не работать, либо работать крайне неэффективно. Об одном моменте следует помнить, переопределяя Equals(): ваша версия этого метода не должна генерировать исключения. В противном случае это может стать причиной проблем для классов словарей, а также, воз­можно, и для других базовых классов .NET, которые внутренне вызывают этот метод.

Статический метод Equals()

Статическая версия Equals() в действительности делает то же самое, что и виртуаль­ная версия уровня экземпляра. Разница в том, что статическая версия принимает два пара­метра и проверяет их на предмет равенства. Этот метод справляется с ситуацией, когда обе ссылки равны null, а потому обеспечивает дополнительную защиту от генерации исключе­ний, когда существует риск, что оба объекта окажутся равными null. Статическая версия первым делом проверяет переданные ей ссылки на предмет равенства их null. Если они обе равны null, возвращается true (поскольку ссылка null трактуется как равная другой ссылке null). Если только одна из ссылок равна null, возвращается false. Если обе ссыл­ки на самом деле указывают на что-либо, вызывается версия Equals() уровня экземпляра. Это значит, что если вы переопределите виртуальный метод Equals() уровня экземпляра, то эффект будет такой, как если бы вы переопределили и статическую версию также.

Операция сравнения (==)

Операцию сравнения можно рассматривать как промежуточный выбор между строгим сравнением значений и строгим сравнением ссылок. В большинстве случаев конструкция

bool b = (х == у) ; // х, у - объектные ссылки

означает, что сравниваются ссылки. Однако возможно существование классов, для кото­рых более естественным и интуитивно ожидаемым будет трактовка сравнения значений. В таких случаях лучше переопределить эту операцию, чтобы она сравнивала значения. Переопределение операций рассматривается ниже, но очевидным примером может слу­жить класс System.String, для которого Microsoft переопределила операцию с тем, что­бы она сравнивала содержимое строк, а не их ссылки.

Проверка типов значений на равенство

При проверке на равенство типов значений сохраняется тот же принцип, что и для ссылочных типов: метод ReferenceEquals() используется для сравнения ссылок, Equals() предназначен для сравнения значений, а операция == имеет промежуточное на­значение. Однако существенное отличие заключается в том, что типы значений нуждаются в упаковке для преобразования их в ссылки, чтобы с ними можно было использовать мето­ды. Вдобавок Microsoft предлагает уже перегруженный метод Equals() в классе System.ValueType, предназначенный для проверки равенства типов значений. Когда вызывается sA.Equals(sB), где sA и sB  экземпляры некоторой структуры, то возвращаемое значе­ние будет true или false  в зависимости от того, содержат ли sA и sB одинаковые значе­ния во всех своих полях. С другой стороны, для структур не предусмотрено по умолчанию никакой перегрузки операции ==. Написание (sA == sB) в любом выражении вызовет ошибку компиляции, если только вы не предусмотрите собственной перегрузки этой опе­рации для таких структур.

Другой важный момент, связанный со сравнением типов значений, состоит в том, что ReferenceEquals() всегда для них возвращает false, поскольку для того, чтобы позво­лить вызов метода, типы значений упаковываются в объекты. Даже если вы напишете

bool b=ReferenceEquals(v,v); //v - переменная некоторого типа значений

то все равно получите false, потому что v будет упакована отдельно при преобразовании' ка­ждого параметра, что означает получение разных ссылок. По этой причине незачем вызывать ReferenceEquals() для сравнения двух типов значений, поскольку это не имеет смысла.

Хотя перегрузка Equals() по умолчанию для System.ValueType почти наверняка по­дойдет для большинства определяемых вами структур, можно переопределить ее собствен­норучно специальным образом, чтобы увеличить производительность. К тому же, если тип значений содержит поля типа ссылок, может понадобиться переопределить Equals(), чтобы предоставить для этих полей соответствующую семантику, поскольку перегрузка Equals() по умолчанию просто сравнивает их адреса.