Учебник по С# | Виртуальные и переопределяющие методы

Задача: создать класс персонажей с методом виртуального недопустимого перемещения.

Краткое содержание

Полиморфизм означает множество форм. В коде полиморфизм позволяет производным классам модифицировать (виртуальные) методы в базовом классе. Все это возможно при использовании виртуальных методов в базовом классе и переопределенииих в производных классах. Это полезно, поскольку вместо создания уникальных имен методов и логики для каждого дочернего объекта. Вместо этого мы можем использовать один метод в базовом классе, изменить метод для каждого отдельного объекта и вызвать метод базового класса.

Пример сценария

Например, базовый класс персонажа с методом для недопустимых ходов. Этот метод по своей основе устанавливает правила того, что считается недопустимым для всех персонажей, но предположим, что у зомби есть определенный шаблон движения, и мы хотим добавить дополнительные ограничения на то, что считается незаконным движением. Без полиморфизма мы должны создать еще один метод Illegal Move Zombie Method с новыми правилами.

Это может быть проблемой, когда у нас много персонажей со своими собственными наборами движений, потому что, когда нам нужно определить тип символ, прежде чем вызывать этот недопустимый ход, и убедитесь, что мы вызываем правильный метод.

foreach (Character monster in character) 
{

    if (monster is Skeleton) 
    {
        Skeleton temp = (Skeleton) monster;
        temp.IllegalMovesSkeleton();
    }

    if (monster is Zombie)
    {
        Zombie temp = (Zombie)monster;
        temp.IllegalMovesZombie();
    }
    monster.IllegalMoves();
}

Как видите, это может быть очень грязно! Например, мне нужно было проверять монстра по отдельности, корректно приводить его и запускать его метод в цикле for-each.

List<Character> character = new List<Character>();

character.Add(new Zombie());
character.Add(new Skeleton());

foreach (Character monster in character) 
{

    if (monster is Skeleton) 
    {
        Skeleton temp = (Skeleton) monster;
        temp.IllegalMovesSkeleton();
    }

    if (monster is Zombie)
    {
        Zombie temp = (Zombie)monster;
        temp.IllegalMovesZombie();
    }
    monster.IllegalMoves();
}

public class Character 
{
    public void IllegalMoves() => Console.WriteLine("OUT OF BOUNDS");
}

public class Zombie: Character 
{
    public  void IllegalMovesZombie() 
    { 
        base.IllegalMoves();
        Console.WriteLine("ZOMBIES CANT WALK FOWARD");
    }
}

public class Skeleton : Character
{
    public  void IllegalMovesSkeleton()
    {
        base.IllegalMoves();
        Console.WriteLine("SKELETONS CANT WALK DIAGONALLY");
    }
}

Сила полиморфизма

С полиморфизмом у нас может быть один метод, который мы можем модифицировать.

foreach (Character monster in character)
monster.IllegalMoves();

Поскольку этот метод находится в базовом классе, все объекты, производные от класса символов, могут вызывать метод недопустимых перемещений, и нам все равно если это скелетилизомби, потому что мы можем переопределить этот метод.

List<Character> character = new List<Character>();

character.Add(new Zombie());
character.Add(new Skeleton());

foreach (Character monster in character)
monster.IllegalMoves();

public class Character 
{
    public  virtual void IllegalMoves() => Console.WriteLine("OUT OF BOUNDS");
}

public class Zombie: Character 
{
    public override void IllegalMoves() 
    { 
        base.IllegalMoves();
        Console.WriteLine("ZOMBIES CANT WALK FOWARD");
    }
}

public class Skeleton : Character
{
    public override void IllegalMoves()
    {
        base.IllegalMoves();
        Console.WriteLine("SKELETONS CANT WALK DIAGONALLY");
    }
}

В заключение, используя KEYWORDS:

public class Character 
{
    public  virtual void IllegalMoves() => Console.WriteLine("OUT OF BOUNDS");
}
  • Виртуальный в базовом классе позволяет производным (дочерним) классам изменять метод с помощью ключевого слова override.
public class Zombie: Character 
{
    public override void IllegalMoves() 
    { 
        base.IllegalMoves();
        Console.WriteLine("ZOMBIES CANT WALK FOWARD");
    }
}

public class Skeleton : Character
{
    public override void IllegalMoves()
    {
        base.IllegalMoves();
        Console.WriteLine("SKELETONS CANT WALK DIAGONALLY");
    }
}
  • Методы переопределения в производном классе должны использовать одно и то же имя, параметры и тип возвращаемого значения. Вы также можете использовать ключевое слово base для вызова исходного метода из базового (родительского) класса.

Конечно, полиморфизм — это еще не все. Например, мы также можем создавать абстрактные и интерфейсные методы для принудительного применения конкретных методов, но это тема для другого разговора!