Книга: C# для профессионалов. Том II
Ссылки на производные классы
Ссылки на производные классы
Подробнее рассмотрим класс Manager
, на который ссылается переменная, объявленная как ссылка на Employee
:
Employee Elton = new Manager("Elton John", 50000.00M);
Это на самом деле совершенно законный синтаксис C#. Правило вполне простое: если объявлена ссылка на некоторый тип данных В, то этой ссылке разрешается ссылаться на экземпляры В или экземпляры любого производного из В класса. Это работает, так как любой класс, производный из В, должен также реализовать все методы или свойства и т.д., которые реализует класс В. Поэтому в примере выше вызывается Elton.Name
, Elton.Salary
и Elton.GetMonthlyPayment()
. Тот факт, что Employee
реализует все эти члены, гарантирует, что любой класс, производный из Employee
, также будет это делать. Поэтому не имеет значения, указывает ли ссылка на производный класс — мы по-прежнему сможем использовать эту ссылку для вызова любого члена класса, на который определена ссылка, и будем уверены, что этот метод существует в производном классе.
С другой стороны, отметим синтаксис, который использовался при вызове свойства Bonus
на объекте Elton
: ((Manager)Elton).Bonus
. В этом случае необходимо явно преобразовать Elton
в ссылку на Manager
, так как Bonus
не реализовано в Employee
. Компилятор знает это и будет создавать ошибку компиляции, если попробовать вызвать Bonus
через ссылку на Employee
. Данная строка кода является на самом деле сокращением записи:
Manager ManagerElton = (Manager)Elton;
this.listBox1.Items.Add("Elton's bonus is " + ManagerElton.Bonus);
Как и в VB, преобразование между типами данных в C# называется преобразованием типов (casting
). Можно заметить в приведенном выше коде, что синтаксис преобразования типов включает размещение имени типа данных в скобках перед именем переменной, преобразование которой собираются выполнить. Конечно, указанный объект должен содержать прежде всего правильный тип данных. Если в этом примере написать:
Manager ManagerBritney = (Manager)Britney;
то код будет компилироваться правильно, но при его работе будет получена ошибка, так как среда выполнения .NET определит, что Britney
является только экземпляром Employee
, а не Manager
. Ссылкам разрешается ссылаться на экземпляры производных классов, но не на экземпляры базовых классов своего собственного типа. Не разрешается ссылке на Manager
ссылаться на объект Employee
. (Это недопустимо, так как подумайте, что произойдет, если попытаться вызвать свойство Bonus с помощью такой ссылки.)
Кстати, совершенно не рассматривались подробности возникновения ошибки во время выполнения. На самом деле C# имеет для такого случая очень развитый механизм, называемый исключениями, который кратко будет показан позже.
Так как VB не поддерживает наследование реализации, то не существует прямой параллели в VB для поддержки ссылок, указывающих на объекты производных классов, как в C#. Однако это напоминает VB — можно объявить ссылку на интерфейс, при этом не имеет значения, на какой тип объекта ссылается интерфейс, пока этот объект реализует интерфейс. Если бы классы Employee
и Manager
кодировались в VB, можно было вполне сделать так, определяя интерфейс IEmployee
, который реализуют оба модуля классов, и затем обращаться к свойствам Employee
через этот интерфейс.