Содержание
При использовании механизма наследовании в 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
В консоли будут следующие строки:
Tom работает в Microsoft
Виртуальные методы базового класса определяют интерфейс всей иерархии классов. Это значит, что в любом производном классе, который не является прямым наследником от базового класса, можно переопределить виртуальные методы. Например, мы можем определить класс Manager
, который будет производным от Employee
, и в нем также переопределить метод Display
.
При переопределении виртуальных методов в C# необходимо учитывать следующие ограничения:
- Виртуальный и переопределенный методы должны иметь один и тот же модификатор доступа. Если виртуальный метод определен с помощью модификатора
public
, то и переопределенный метод также должен иметь модификаторpublic
. - Нельзя переопределить или объявить виртуальным статический метод.
Переопределение свойств в 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
.