Классы и объекты C#: виртуальные методы и свойства

При использовании механизма наследовании в C# достаточно часто появляется необходимость изменить в классе-наследнике функционал метода, который был унаследован от предка (базового класса). Для этого, в C# класс-наследник может переопределять методы и свойства базового класса. Те методы или свойства, которые мы хотим сделать доступными для переопределения, в базовом классе помечается модификатором virtual. Такие методы и свойства обычно называют виртуальными.

Переопределение методов в C#

Чтобы переопределить метод в классе-наследнике, этот метод определяется с в классе модификатором override. В отличие от перегрузки, переопределенный метод в классе-наследнике должен иметь тот же набор параметров, что и виртуальный метод в базовом классе. Например, рассмотрим следующие классы:

class Person
{
    public string Name { get; set; }
    public Person(string name)
    {
        Name = name;
    }
    public virtual void Display()
    {
        Console.WriteLine(Name);
    }
}
class Employee : Person
{
    public string Company { get; set; }
    public Employee(string name, string company) : base(name)
    {
        Company = company;
    }
}

Класс Person представляет человека. В свою очередь, класс Employee наследуется от Person и представляет сотрудника организации и, кроме унаследованного свойства Name, имеет еще одно свойство — Company. Чтобы сделать метод Display доступным для переопределения, этот метод определен с модификатором virtual, что и было сделано в примере. Поэтому мы можем переопределить этот метод (а можем и не переопределять — всё зависит от наших потребностей).

Допустим, что нас устраивает реализация метода из базового класса. В таком случае, объекты Employee будут использовать реализацию метода Display из класса Personкак есть:

    Person p1 = new Person("Вася");
    p1.Display(); // вызов метода Display из класса Person

    Employee e1 = new Employee("Билл", "Microsoft");
    e1.Display(); // вызов метода Display из класса Person

В консоли мы увидим следующее:

Вася

Билл

Если же нас не устраивает функционал метода Display в родителе, то мы можем переопределить виртуальный метод. Для этого в классе-наследнике определяется метод с модификатором override, который имеет то же самое имя и набор параметров (сигнатуру):

class Employee : Person
{
    public string Company { get; set; }
    public Employee(string name, string company): base(name)
    {
        Company = company;
    }

    public override void Display()
    {
        Console.WriteLine($"{Name} работает в {Company}");
    }
}

Пример использования:

    Person p1 = new Person("Bill");
    p1.Display(); // вызов метода Display из класса Person

    Employee p2 = new Employee("Tom", "Microsoft");
    p2.Display(); // вызов метода Display из класса Employee

В консоли будут следующие строки:

Bill

Tom работает в Microsoft

Виртуальные методы базового класса определяют интерфейс всей иерархии классов. Это значит, что в любом производном классе, который не является прямым наследником от базового класса, можно переопределить виртуальные методы. Например, мы можем определить класс Manager, который будет производным от Employee, и в нем также переопределить метод Display.

При переопределении виртуальных методов в C# необходимо учитывать следующие ограничения:

  1. Виртуальный и переопределенный методы должны иметь один и тот же модификатор доступа. Если виртуальный метод определен с помощью модификатора public, то и переопределенный метод также должен иметь модификатор public.
  2. Нельзя переопределить или объявить виртуальным статический метод.

Переопределение свойств в C#

В C# можно переопределять как методы, так и свойства базовых классов:

class Credit
{
    public virtual decimal Sum { get; set; }
}

class LongCredit : Credit
{
    private decimal sum;
    //переопределенное свойство
    public override decimal Sum
    {
        get
        {
            return sum;
        }
        set
        {
            if(value > 1000)
            {
                sum = value;
            }
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        LongCredit credit = new LongCredit { Sum = 6000 };
        credit.Sum = 490;
        Console.WriteLine(credit.Sum);
    }
}

Ключевое слово base

С использованием ключевого слова base мы можем обращаться к членам базового класса. В нашем случае вызов base.Display(); позволяет обратиться к методу Display() в классе Person:

class Employee : Person
{
    public string Company { get; set; }
 
    public Employee(string name, string company)
            :base(name)
    {
        Company = company;
    }
 
    public override void Display()
    {
        base.Display();
        Console.WriteLine($"работает в {Company}");
    }
}

Запрет переопределения методов

Бывает необходимо также запретить переопределение методов и свойств в классах-наследниках. В этом случае методы и свойства необходимо объявлять с модификатором sealed:

class Employee : Person
{
    public string Company { get; set; }
 
    public Employee(string name, string company): base(name)
    {
        Company = company;
    }
    //ни один наследник Employee не сможет переопределить этот метод
    public override sealed void Display()
    {
        Console.WriteLine($"{Name} работает в {Company}");
    }
}

При создании методов с модификатором sealed следует учитывать, что ключевое слово sealed применяется в паре с override, то есть только в переопределяемых методах.

Итого

Сегодня мы познакомились с такой замечательной возможностью языка C# как переопределение методов и свойств. Узнали как определять в классах виртуальные методы, переопределять методы и свойства в наследниках, а также обращаться к членам и методам базовых классов, используя ключевое слово base и запрещать переопределять методы с использованием ключевого слова sealed.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии