Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
Нетрудно догадаться, что есть многие другие детали наследования, о которых вы узнаете в оставшемся материале главы. Пока просто примите к сведению, что операция двоеточия позволяет устанавливать отношения "базовый-производный" между классами, а ключевое слово sealed предотвращает последующее наследование.
Еще раз о диаграммах классов Visual Studio
В главе 2 кратко упоминалось о том, что среда Visual Studio позволяет устанавливать отношения "базовый-производный" между классами визуальным образом во время проектирования. Для работы с указанным аспектом IDE-среды сначала понадобится добавить в текущий проект новый файл диаграммы классов. Выберите пункт меню Project►Add New Item (Проект►Добавить новый элемент) и щелкните на значке Class Diagram (Диаграмма классов); на рис. 6.1 видно, что файл был переименован с ClassDiagraml.cd на Cars.cd.
После щелчка на кнопке Add (Добавить) отобразится пустая поверхность проектирования. Чтобы добавить типы в визуальный конструктор классов, просто перетаскивайте на эту поверхность каждый файл из окна Solution Explorer (Проводник решений). Также вспомните, что удаление элемента из визуального конструктора (путем его выбора и нажатия клавиши <Delete>) не приводит к уничтожению ассоциированного с ним исходного кода, а просто убирает элемент из поверхности конструктора. Текущая иерархия классов показана на рис. 6.2.
Как говорилось в главе 2. помимо простого отображения отношений между типами внутри текущего приложения можно также создавать новые типы и наполнять их членами, применяя панель инструментов конструктора классов и окно Class Details (Детали класса).
При желании можете свободно использовать указанные визуальные инструменты во время проработки оставшихся глав книги. Однако всегда анализируйте сгенерированный код, чтобы четко понимать, что эти инструменты для вас сделали.
Второй принцип объектно-ориентированного программирования: детали наследования
Теперь, когда вы видели базовый синтаксис наследования, давайте построим более сложный пример и рассмотрим многочисленные детали построения иерархий классов. Мы снова обратимся к классу Employee, который был спроектирован в главе 5. Первым делом создайте новый проект консольного приложения C# по имени Employees.
Далее скопируйте в проект Employees файлы Employee.cs, Employee.Core.cs и EmployeePayTypeEnum.cs, созданные ранее в проекте EmployeeApp из главы 5.
На заметку! До выхода .NET Core, чтобы использовать файлы в проекте С#, на них необходимо было ссылаться в файле .csproj. В версии .NET Core все файлы из текущей структуры каталогов автоматически включаются в проект. Простого копирования нескольких файлов из другого проекта достаточно для их включения в ваш проект.
Прежде чем приступать к построению каких-то производных классов, следует уделить внимание одной детали. Поскольку первоначальный класс Employee был создан в проекте по имени EmployeeApp, он находится внутри идентично названного пространства имен .NET Core. Пространства имен подробно рассматриваются в главе 16; тем не менее, ради простоты переименуйте текущее пространство имен (в обоих файлах) на Employees, чтобы оно совпадало с именем нового проекта:
// Не забудьте изменить название пространства имен в обоих файлах С#!
namespace Employees
{
partial class Employee
{...}
}
На заметку! Если вы удалили стандартный конструктор во время внесения изменений в код класса Employee в главе 5, тогда снова добавьте его в класс.
Вторая деталь касается удаления любого закомментированного кода из различных итераций класса Employee, рассмотренных в примере главы 5.
На заметку! В качестве проверки работоспособности скомпилируйте и запустите новый проект, введя dotnet run в окне командной подсказки (в каталоге проекта) или нажав <Ctrl+F5> в случае использования Visual Studio. Пока что программа ничего не делает, но это позволит удостовериться в отсутствии ошибок на этапе компиляции.
Цель в том, чтобы создать семейство классов, моделирующих разнообразные типы сотрудников в компании. Предположим, что необходимо задействовать функциональность класса Employee при создании двух новых классов (SalesPerson и Manager). Новый класс SalesPerson "является" Employee (как и Manager). Вспомните, что в модели классического наследования базовые классы (вроде Employee) обычно применяются для определения характеристик, общих для всех наследников. Подклассы (такие как SalesPerson и Manager) расширяют общую функциональность, добавляя к ней специфическую функциональность.
В настоящем примере мы будем считать, что класс Manager расширяет Employee, сохраняя количество фондовых опционов, тогда как класс SalesPerson поддерживает хранение количества продаж. Добавьте новый файл класса (Manager.cs), в котором определен класс Manager со следующим автоматическим свойством:
// Менеджерам нужно знать количество их фондовых опционов.
class Manager : Employee
{
public int StockOptions { get; set; }
}
Затем добавьте еще один новый файл класса (SalesPerson.cs), в котором определен класс SalesPerson с подходящим автоматическим свойством:
// Продавцам нужно знать количество продаж.
class SalesPerson : Employee
{
public int SalesNumber { get; set; }
}
После того как отношение "является" установлено, классы SalesPerson и Manager автоматически наследуют все открытые члены базового класса Employee. В целях иллюстрации обновите операторы верхнего уровня, как показано ниже:
// Создание объекта подкласса и доступ к функциональности базового класса.
Console.WriteLine("***** The Employee Class Hierarchy *****n");
SalesPerson fred = new SalesPerson
{
Age = 31, Name = "Fred", SalesNumber = 50
};
Вызов конструкторов базового класса с помощью ключевого слова base
В текущий момент объекты классов SalesPerson и Manager могут создаваться только с использованием "бесплатно полученного" стандартного конструктора (см. главу 5). Памятуя о данном факте, предположим, что в класс Manager добавлен новый конструктор с шестью аргументами, который вызывается следующим образом:
...
// Предположим, что у Manager есть конструктор с такой сигнатурой:
// (string fullName, int age, int empId,
// float currPay, string ssn, int numbOfOpts)
Manager chucky = new Manager("Chucky", 50, 92, 100000, "333-23-2322", 9000);
Взглянув на список