Ключевые слова Virtual и Override
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy. Урок 21 из 70.
Когда производный класс наследует метод, иногда нужно полностью изменить поведение этого метода. Ключевые слова virtual и override работают вместе, позволяя сделать это контролируемым образом.
Пометь метод как virtual в базовом классе, чтобы указать, что производные классы могут заменить его реализацию:
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("Some sound");
}
}
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Woof!");
}
}Ключевое слово override в производном классе сообщает компилятору, что ты намеренно заменяешь метод базового класса. Если базовый метод не помечен ключевым словом virtual, использовать override нельзя.
Настоящая мощь проявляется, когда вы используете ссылку на базовый класс для хранения производного объекта:
Animal myPet = new Dog();
myPet.Speak(); // Вывод: Woof!Хотя myPet объявлена как Animal, C# вызывает версию Dog метода Speak(). Это называется полиморфизмом времени выполнения — фактически вызываемый метод зависит от истинного типа объекта, а не от объявленного типа переменной.
Если ты хочешь расширить поведение, а не полностью заменить его, то в переопределённом методе можно по-прежнему вызвать базовую реализацию с помощью base.Speak().
Задание
ЛегкоДавайте создадим систему уведомлений, которая покажет, как производные классы могут полностью переопределять поведение базового класса с помощью ключевых слов virtual и override, а также продемонстрирует возможности полиморфизма во время выполнения.
Вы создадите три файла, чтобы упорядочить код:
Notification.cs: Определите классNotificationв пространстве имёнAlerts. Этот базовый класс представляет общее уведомление со свойствомMessage(строка) и конструктором, который задаёт его значение. Добавьте методvirtualс именемSend(), который возвращает"Sending notification: {Message}".EmailNotification.cs: Определите классEmailNotificationв пространстве имёнAlerts, наследующийNotification. Добавьте свойствоRecipient(строка) и конструктор, принимающий и сообщение, и получателя (используйтеbase, чтобы передать сообщение). Переопределите методSend(), чтобы он возвращал"Emailing {Recipient}: {Message}".SmsNotification.cs: Определите классSmsNotificationв пространстве имёнAlerts, который также наследуетNotification. Добавьте свойствоPhoneNumber(строка) и конструктор, принимающий и сообщение, и номер телефона. ПереопределитеSend(), чтобы он возвращал"SMS to {PhoneNumber}: {Message}".Program.cs: В основном файле создайте экземпляры всех трёх типов уведомлений, используя входные значения. Затем продемонстрируйте полиморфизм во время выполнения, сохранив все три экземпляра в переменных типаNotificationи вызвав для каждого из нихSend().
На вход будут поданы четыре значения:
- Текст уведомления
- Адрес электронной почты получателя
- Номер телефона для SMS
Выведите результат вызова Send() для каждого уведомления, сохранённого в ссылке на базовый класс:
{base notification Send() result}
{email notification Send() result}
{sms notification Send() result}Например, если на вход поданы Meeting at 3pm, alice@email.com и 555-1234, вывод должен быть таким:
Sending notification: Meeting at 3pm
Emailing alice@email.com: Meeting at 3pm
SMS to 555-1234: Meeting at 3pmОбратите внимание: хотя все три экземпляра хранятся в переменных типа Notification, для каждого вызывается собственная переопределённая версия Send(). Это и есть полиморфизм во время выполнения!
Попробуйте сами
using System;
using Alerts;
class Program
{
public static void Main(string[] args)
{
// Считайте входные данные
string message = Console.ReadLine();
string email = Console.ReadLine();
string phone = Console.ReadLine();
// TODO: Создайте экземпляры всех трёх типов уведомлений
// Сохраните их в переменных типа Notification, чтобы продемонстрировать полиморфизм
// TODO: Создайте базовый объект Notification
Notification baseNotification;
// TODO: Создайте объект EmailNotification (сохраните его в переменной типа Notification)
Notification emailNotification;
// TODO: Создайте объект SmsNotification (сохраните его в переменной типа Notification)
Notification smsNotification;
// TODO: Вызовите Send() для каждого объекта и выведите результаты
// Благодаря полиморфизму во время выполнения будут вызваны переопределённые методы
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методовПотренируйтесь самостоятельно: Онлайн-компилятор C#