Изучение полиморфизма на основе наследования
Полиморфизм на основе наследования основан на иерархии классов, где производные классы наследуют поведение и свойства базового класса. Отношение наследования позволяет рассматривать объекты производных классов как объекты базового класса. Возможность рассматривать производные объекты класса как объекты базового класса позволяет писать код, который работает с несколькими типами объектов, не зная конкретный тип во время компиляции.
В следующем примере кода демонстрируется полиморфизм на основе наследования в C#:
// Base class
public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("The animal makes a sound.");
}
}
// Derived class Dog
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("The dog barks.");
}
}
// Derived class Cat
public class Cat : Animal
{
public override void MakeSound()
{
Console.WriteLine("The cat meows.");
}
}
// Derived class Cow
public class Cow : Animal
{
public override void MakeSound()
{
Console.WriteLine("The cow moos.");
}
}
class Program
{
static void Main()
{
// Create an array of Animal objects
Animal[] animals = new Animal[3];
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Cow();
animals[0] = animal1;
animals[1] = animal2;
animals[2] = animal3;
// Demonstrate polymorphism
foreach (Animal animal in animals)
{
animal.MakeSound();
}
}
}
В этом примере кода обратите внимание, что класс Program создает массив объектов Animal и назначает экземпляры Dog, Catи Cow элементам массива. Метод MakeSound вызывается для каждого объекта в массиве, демонстрируя полиморфизм. Метод MakeSound переопределяется в производных классах, чтобы обеспечить определенное поведение для каждого типа животных.
Приведение объекта базового класса к производного класса
Приведение в C# — это процесс преобразования объекта одного типа в другой тип. Приведение часто используется при реализации полиморфизма с помощью иерархий наследования, где имеется базовый класс и один или несколько производных классов.
Существует два основных типа приведения:
Неявное приведение: это происходит автоматически при преобразовании производного класса в базовый класс. Это безопасно, так как каждый экземпляр производного класса также является экземпляром базового класса.
BankAccount account = new CheckingAccount();Явное приведение. Для этого требуется оператор приведения и используется при преобразовании базового класса в производный класс. Это не всегда безопасно, так как не каждый экземпляр базового класса является экземпляром производного класса.
CheckingAccount checkingAccount = (CheckingAccount)account;
Приведение объектов с помощью ключевых слов is и as
В C# можно приводить объекты с помощью ключевых слов is и as. Эти ключевые слова обеспечивают безопасный способ проверки типа объекта перед приведением его к другому типу. Ниже приведены некоторые распространенные способы приведения объектов в C#:
Использование ключевого слова
isс сопоставлением шаблонов:if (account is CheckingAccount checkingAccount) { // Use checkingAccount as a CheckingAccount }- Этот синтаксис проверяет, имеет ли
accountтипCheckingAccount. - Если проверка выполнена успешно, она приводит
accountкCheckingAccountи назначает ее переменнойcheckingAccount. - Этот подход является кратким и безопасным, так как он объединяет проверку типа и приведение на одном шаге.
- Этот синтаксис проверяет, имеет ли
Использование ключевого слова
is, за которым следует явное приведение:if (account is CheckingAccount) { CheckingAccount checkingAccount = (CheckingAccount)account; // Use checkingAccount as a CheckingAccount }- Этот синтаксис проверяет, имеет ли
accountтипCheckingAccount. - Если проверка выполнена успешно, она явно приводит
accountкCheckingAccountи назначает ее переменнойcheckingAccount. - Этот подход более подробный, чем синтаксис сопоставления шаблонов, но обеспечивает больший контроль над процессом приведения.
- Этот синтаксис проверяет, имеет ли
Использование ключевого слова
as:CheckingAccount checkingAccount = account as CheckingAccount; if (checkingAccount != null) { // Use checkingAccount as a CheckingAccount }- Этот синтаксис пытается привести
accountкCheckingAccountи назначает результатcheckingAccount. - Если приведение выполнено успешно,
checkingAccountсодержит объект приведения; в противном случае значение null. - Этот подход полезен, если необходимо проверить результат приведения перед использованием объекта приведения. Например, если вы хотите избежать исключений и корректно обрабатывать случай сбоя.
- Этот синтаксис пытается привести
При реализации приведения рассмотрите следующие рекомендации.
- Использование сопоставления шаблонов с
is: объединяет проверку типа и приведение на одном шаге. - Использование ключевого слова
isс явным приведением: разделяет проверку типа и приведение на два шага, обеспечивая больше контроля над процессом приведения. - Используя ключевое слово
as: пытается привести и обрабатывает сбой, возвращая значение NULL.
- Использование сопоставления шаблонов с
Понимание этих методов приведения является важным для работы с полиморфизмом и наследованием в C#.
Избегайте распространенных ошибок при реализации полиморфизма
Когда ваша цель состоит в полиморфизме на основе наследования, вот некоторые вещи, чтобы избежать, и некоторые вещи, чтобы обеспечить следующее:
Избегайте использования запечатанных классов и методов: запечатанные классы и методы не могут быть унаследованы или переопределены, что ограничивает возможность использования полиморфизма. Если вы запечатываете класс или метод, вы не можете продолжить расширение и настройку. Например:
public sealed class BankAccount { } // This class can't be inheritedИзбегайте чрезмерного использования статических методов. Статические методы относятся к самому классу, а не экземпляру класса. Они не могут быть переопределены, что означает, что они не участвуют в полиморфизме.
public static void PrintMessage() { } // This method can't be overriddenИзбегайте жесткой связи. Жесткое связывание происходит, когда классы или компоненты в системе сильно зависят друг от друга. Это означает, что изменения в одном классе могут напрямую влиять на другие классы, что делает систему менее гибкой и сложной для поддержания. Жесткое связывание может привести к трудностям при тестировании, расширении и изменении кода.
public class BankAccount { public void TransferFunds(SavingsAccount savingsAccount) { // Tight coupling with SavingsAccount } }Избегайте использования ключевого слова new без хорошей причины. Ключевое слово "new" скрывает метод базового класса в производном классе, что может привести к путанице и неожиданному поведению. Используйте только ключевое слово new, если планируется скрыть метод базового класса намеренно.
public class Dog : Animal { public new void MakeSound() // Hides the base class method. Better to use 'override' { Console.WriteLine("The dog barks."); } }Убедитесь, что согласованные подписи методов. Убедитесь, что переопределенные методы в производных классах имеют ту же сигнатуру, что и метод базового класса. Изменение сигнатуры метода приведет к скрытию метода, а не переопределении.
public class Animal { public virtual void MakeSound(string sound) { Console.WriteLine("The animal makes a sound."); } } public class Dog : Animal { // Method signature doesn't match the base class public override void MakeSound() { Console.WriteLine("The dog barks."); } }
Сводка
Полиморфизм на основе наследования в C# позволяет создать иерархию классов, в которых производные классы наследуют поведение и свойства базового класса. Этот механизм наследования позволяет рассматривать объекты производных классов как объекты базового класса. Возможность рассматривать производные объекты класса как члены базового класса позволяет писать код, который работает с несколькими типами объектов, не зная конкретный тип во время компиляции. Понимая методы приведения, избегая распространенных ошибок и следуя рекомендациям, вы можете эффективно реализовать полиморфизм в приложениях C#.