Разработка приложений на языке C#. Полезные настройки. Особые спецификаторы формата, страница 18

В классе Man появится заготовка переопределенной версии метода Equals. Замените параметр obj на other (так понятней). В теле метода Equals надо сравнить два объекта и вернуть результат булевского типа. Какие два объекта сравнивать? Сравните объект, которому послано сообщение Equals, с тем объектом, который задан параметром.

Заметьте, что он имеет тип ссылки на родительский класс object. Вспомните правило ООП: «родители могут указывать на детей, но дети не могут этого делать» и измените код функции Equals так, чтобы она возвращала true только если два объекта идентичны (равны по сути, а не по адресу). Объекты должны сравниваться, опираясь на их содержимое, а не значения адресов. Если аргументом окажется ссылка на объект какого-либо другого типа, то метод должен вернуть false. Этого можно добиться несколькими способами:

·  Используем try-catchtry { Man m = (Man)other; return m.name == name && m.age == age; } catch { return false; }

·  Используем операцию is. if (other is Man) { Man m = (Man)other; return . . . ; } else return false;

·  Используем операцию as. Man m = other as Man; return m==null ? false : m.name == name && m.age == age;

Определение бинарных операций

Метод Equals унаследован от object'а. Но вы можете пользоваться и операцией == (переопределив ее смысл для объектов класса Man). Заметьте, что это делать не рекомендуется, так как во многих случаях необходимо сравнивать адреса, а не сущности. Если вы хотите сравнивать сущности используйте метод Equals, а операцию == оставьте для сравнения ссылок. Именно для этой цели класс object и передает всем классам .NET метод Equals. Метод Equals вызывается в алгоритмах поиска объектов внутри массивов и динамических коллекций.  В частности, его вызывает метод Array.IndexOf. Если вы, тем не менее, захотите переопределить операцию == для объектов класса Man, то прочтите следующий абзац.

В отличие от С++, где есть некоторая свобода при выборе способа переопределения бинарной операции (в виде метода с 1-м параметром или friend-функции с 2-мя параметрами), в C# возможен только один способ — в виде статического метода с двумя параметрами. Это устраняет произвол и делает язык более строгим. Следуя этому правилу, введите определение операции ==. При этом вам придется переопределить и операцию !=. В теле метода operator==() можно использовать вызов уже созданной версии Equals. Запустите и проверьте результат сравнения ken==men[0] (до переселения ken'а и после).

Обратите внимание на предупреждения в окне Output. Они означают, что нехорошо переопределять Equals или operator==, но не трогать при этом виртуальную функцию GetHashCode. Она используется при работе с коллекциями типа Dictionary (HashTable, SortedList), или коллекций, произведенных от NameObjectCollectionBase.

Метод GetHashCode

Несмотря на то, что мы пока не пользуемся коллекцией типа Hashtable, тем не менее объекты класса Man уже могут получить свои hash-ключи, так как функция GetHashCode унаследована от класса Object и доступна для наших объектов. Вы можете увидеть какие значения будут сопоставлены объектам класса Man.

Замените последний фрагмент проверки равенства ссылок на тот, что приведен ниже. В нем мы (совместно) проверяем и равенство объектов и равенство их hash-ключей. Важно, что мы делаем это как до переселения men[0], так и после этого.

//===== Проверка равенства ссылок (?)  Объясните все три результата сравнения !!

Console.WriteLine("\n=====Test Equility and Hash keys=====\n");

Console.WriteLine("ken.Equals(men[0]) = {0}", ken.Equals(men[0]));

Console.WriteLine("men[0].Equals(men[3]) = {0}", men[0].Equals(men[3]));

Console.Write("\nHash keys: ");

foreach (Man m in men) // Пользуемся родительской версией функции GetHashCode

  Console.Write("{0}, ", m.GetHashCode());

men[0] = new Man("Ken Wood", 40);

Console.Write("\nHash keys: ");

foreach (Man m in men)

  Console.Write("{0}, ", m.GetHashCode());