Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

public override bool Equals(object obj)

{

if (!(obj is Person temp))

{

return false;

}

if (temp.FirstName == this.FirstName

&& temp.LastName == this.LastName

&& temp.Age == this.Age)

{

return true;

}

return false;

}

Здесь

производится сравнение значений входного объекта с внутренними значениями текущего объекта (обратите внимание на применение ключевого слова
this
). Если имя, фамилия и возраст в двух объектах идентичны, то эти два объекта имеют одинаковые данные состояния и возвращается значение
true
. Любые другие результаты приводят к возвращению
false
.

Хотя такой подход действительно работает, вы определенно в состоянии представить, насколько трудоемкой была бы реализация специального метода

Equals
для нетривиальных типов, которые могут содержать десятки полей данных. Распространенное сокращение предусматривает использование собственной реализации метода
ToString
. Если класс располагает подходящей реализацией
ToString
, в которой учитываются все поля данных вверх по цепочке наследования, тогда можно просто сравнивать строковые данные объектов (проверив на равенство
null
):

// Больше нет необходимости приводить obj к типу Person,

// т.к. у всех типов имеется метод ToString.

public override bool Equals(object obj)

=> obj?.ToString == ToString;

Обратите внимание, что в этом случае нет необходимости проверять входной аргумент на принадлежность к корректному типу (

Person
в нашем примере), поскольку метод
ToString
поддерживают все типы .NET. Еще лучше то, что больше не требуется выполнять проверку на предмет равенства свойство за свойством, т.к. теперь просто проверяются значения, возвращаемые методом
ToString
.

Переопределение метода System.Object.GetHashCode

В случае переопределения в классе метода

Equals
вы также должны переопределить стандартную реализацию метода
GetHashCode
. Выражаясь упрощенно, хеш-код — это числовое значение, которое представляет объект как специфическое состояние. Например, если вы создадите две переменные типа
string
, хранящие значение
Hello
, то они должны давать один и тот же хеш-код. Однако если одна из них хранит строку в нижнем регистре (
hello
), то должны получаться разные хеш-коды.

Для выдачи хеш-значения метод

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

На заметку! Говоря точнее, класс

System.Collections.Hashtable
внутренне вызывает метод
GetHashCode
, чтобы получить общее представление о местоположении объекта, а
с помощью последующего (внутреннего) вызова метода
Equals
определяет его точно.

Хотя в настоящем примере мы не собираемся помещать объекты

Person
внутрь
System.Collections.Hashtable
, ради полноты изложения давайте переопределим метод
GetHashCode
. Существует много алгоритмов, которые можно применять для создания хеш-кода, как весьма изощренных, так и не очень. В большинстве ситуаций есть возможность генерировать значение хеш-кода, полагаясь на реализацию метода
GetHashCode
из класса
System.String
.

Учитывая, что класс

String
уже имеет эффективный алгоритм хеширования, использующий для вычисления хеш-значения символьные данные объекта
String
, вы можете просто вызвать метод
GetHashCode
с той частью полей данных, которая должна быть уникальной во всех экземплярах (вроде номера карточки социального страхования), если ее удается идентифицировать. Таким образом, если в классе
Person
определено свойство
SSN
, то вы могли бы написать следующий код:

// Предположим, что имеется свойство SSN.

class Person

{

public string SSN {get; } = "";

public Person(string fName, string lName, int personAge,

string ssn)

{

FirstName = fName;

LastName = lName;

Age = personAge;

SSN = ssn;

}

// Возвратить хеш-код на основе уникальных строковых данных.

public override int GetHashCode => SSN.GetHashCode;

}

В случае использования в качестве основы хеш-кода свойства, допускающего чтение и запись, вы получите предупреждение. После того, как объект создан, хеш-код должен быть неизменяемым. В предыдущем примере свойство

SSN
имеет только метод
get
, что делает его допускающим только чтение, и устанавливать его можно только в конструкторе.

Если вы не можете отыскать единый фрагмент уникальных строковых данных, но есть переопределенный метод

ToString
, который удовлетворяет соглашению о доступе только по чтению, тогда вызывайте
GetHashCode
на собственном строковом представлении:

// Возвратить хеш-код на основе значения, возвращаемого

// методом ToString для объекта Person.

public override int GetHashCode => ToString.GetHashCode;

Тестирование модифицированного класса Person

Теперь, когда виртуальные члены класса

Object
переопределены, обновите операторы верхнего уровня, чтобы протестировать внесенные изменения:

Console.WriteLine("***** Fun with System.Object *****\n");

// ПРИМЕЧАНИЕ: мы хотим, чтобы эти объекты были идентичными

// в целях тестирования методов Equals и GetHashCode.

Person p1 = new Person("Homer", "Simpson", 50, "111-11-1111");

Поделиться с друзьями: