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

ЖАНРЫ

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

Чтобы проиллюстрировать стандартное поведение, обеспечиваемое базовым классом

Object
, создайте новый проект консольного приложения C# по имени
ObjectOverrides
.

Добавьте в проект новый файл класса С#, содержащий следующее пустое определение типа

Person
:

// Не забывайте, что класс Person расширяет Object.

class Person {}

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

System.Object
:

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

Person p1 = new Person;

//
Использовать унаследованные члены System.Object.

Console.WriteLine("ToString: {0}", p1.ToString);

Console.WriteLine("Hash code: {0}", p1.GetHashCode);

Console.WriteLine("Type: {0}", p1.GetType);

// Создать другие ссылки на pi.

Person p2 = p1;

object o = p2;

// Указывают ли ссылки на один и тот же объект в памяти?

if (o.Equals(p1) && p2.Equals(o))

{

Console.WriteLine("Same instance!");

}

Console.ReadLine;

}

Вот вывод, получаемый в результате выполнения этого кода:

***** Fun with System.Object *****

ToString: ObjectOverrides.Person

Hash code: 58225482

Type: ObjectOverrides.Person

Same instance!

Обратите внимание на то, что стандартная реализация

ToString
возвращает полностью заданное имя текущего типа (
ObjectOverrides.Person
). Как будет показано в главе 15, где исследуется построение специальных пространств имен, каждый проект C# определяет "корневое пространство имен", название которого совпадает с именем проекта. Здесь мы создали проект по имени
ObjectOverrides
, поэтому тип
Person
и класс
Program
помещены внутрь пространства имен
ObjectOverrides
.

Стандартное поведение метода

Equals
заключается в проверке, указывают ли две переменные на один и тот же объект в памяти. В коде мы создаем новую переменную
Person
по имени
pi
. В этот момент новый объект
Person
помещается в управляемую кучу. Переменная
р2
также относится к типу
Person
. Тем не менее, вместо создания нового экземпляра переменной
р2
присваивается ссылка
pi
. Таким образом, переменные
pi
и
р2
указывают на один и тот же объект в памяти, как и переменная
о
(типа
object
). Учитывая, что
pi
,
р2
и
о
указывают на одно и то же местоположение в памяти, проверка эквивалентности дает положительный результат.

Хотя готовое поведение

System.Object
в ряде случаев может удовлетворять всем потребностям, довольно часто в специальных типах часть этих унаследованных методов переопределяется. В целях иллюстрации модифицируем класс
Person
, добавив свойства, которые представляют имя, фамилию и возраст лица; все они могут быть установлены с помощью специального конструктора:

// Не забывайте,
что класс Person расширяет Object.

class Person

{

public string FirstName { get; set; } = "";

public string LastName { get; set; } = "";

public int Age { get; set; }

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

{

FirstName = fName;

LastName = lName;

Age = personAge;

}

public Person{}

}

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

Многие создаваемые классы (и структуры) могут извлечь преимущества от переопределения метода

ToString
для возвращения строки с текстовым представлением текущего состояния экземпляра типа. Помимо прочего это полезно при отладке. То, как вы решите конструировать результирующую строку — дело личных предпочтений; однако рекомендуемый подход предусматривает отделение пар "имя-значение" друг от друга двоеточиями и помещение всей строки в квадратные скобки (такому принципу следуют многие типы из библиотек базовых классов .NET Core). Взгляните на следующую переопределенную версию
ToString
для класса
Person
:

public override string ToString

=> $"[First Name: {FirstName}; Last Name: {LastName};

Age:
{Age}]";

Приведенная реализация метода

ToString
довольно прямолинейна, потому что класс
Person
содержит всего три порции данных состояния. Тем не менее, всегда помните о том, что правильное переопределение
ToString
должно также учитывать любые данные, определенные выше в цепочке наследования.

При переопределении метода

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

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

Давайте также переопределим поведение метода

Object.Equals
, чтобы работать с семантикой на основе значений. Вспомните, что по умолчанию
Equals
возвращает
true
, только если два сравниваемых объекта ссылаются на один и тот же экземпляр объекта в памяти. Для класса
Person
может оказаться полезной такая реализация
Equals
, которая возвращает
true
, если две сравниваемые переменные содержат те же самые значения состояния (например, фамилию, имя и возраст).

Прежде всего, обратите внимание, что входной аргумент метода

Equals
имеет общий тип
System.Object
. В связи с этим первым делом необходимо удостовериться в том, что вызывающий код действительно передал экземпляр типа
Person
, и для дополнительной подстраховки проверить, что входной параметр не является ссылкой
null
.

После того, как вы установите, что вызывающий код передал выделенный экземпляр

Person
, один из подходов предусматривает реализацию метода
Equals
для сравнения поле за полем данных входного объекта с данными текущего объекта:

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