Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

static void GivePromotion(Employee emp)

{

// Повысить зарплату...

// Предоставить место на парковке компании...

Console.WriteLine("{0} was promoted!", emp.Name);

}

Из-за того, что данный метод принимает единственный параметр типа

Employee
, в сущности, ему можно передавать объект любого унаследованного от
Employee
класса, учитывая наличие отношения "является":

static void CastingExamples

{

// Manager "является" System.Object,
поэтому в переменной

// типа object можно сохранять ссылку на Manager.

object frank = new Manager("Frank Zappa", 9, 3000, 40000, "111-11-1111", 5);

// Manager также "является" Employee.

Employee moonUnit = new Manager("MoonUnit Zappa", 2, 3001, 20000,

"101-11-1321", 1);

GivePromotion(moonUnit);

// PtSalesPerson "является" SalesPerson.

SalesPerson jill = new PtSalesPerson("Jill", 834, 3002, 100000,

"111-12-1119", 90);

GivePromotion(jill);

}

Предыдущий код компилируется благодаря неявному приведению от типа базового класса (

Employee
) к производному классу. Но что, если вы хотите также вызвать метод
GivePromotion
с объектом
frank
(хранящимся в общей ссылке
System.Object
)? Если вы передадите объект
frank
методу
GivePromotion
напрямую, то получите ошибку на этапе компиляции:

object frank = new Manager("Frank Zappa", 9, 3000, 40000, "111-11-1111", 5);

// Ошибка!

GivePromotion(frank);

Проблема в том, что вы пытаетесь передать переменную, которая объявлена как принадлежащая не к типу

Employee
, а к более общему типу
System.Object
. Учитывая, что в цепочке наследования он находится выше, чем
Employee
, компилятор не разрешит неявное приведение, стараясь сохранить ваш код насколько возможно безопасным в отношении типов.

Несмотря на то что сами вы можете выяснить, что ссылка

object
указывает в памяти на объект совместимого с
Employee
класса, компилятор сделать подобное не в состоянии, поскольку это не будет известно вплоть до времени выполнения. Чтобы удовлетворить компилятор, понадобится применить явное приведение, которое и является вторым правилом: в таких случаях вы можете явно приводить "вниз", используя операцию приведения С#. Базовый шаблон, которому нужно следовать при выполнении явного приведения, выглядит так:

(класс_к_которому_нужно_привести) существующая_ссылка

Таким образом, чтобы передать переменную типа

object
методу
GivePromotion
, потребуется написать следующий код:

// Правильно!

GivePromotion((Manager)frank);

Использование ключевого слова as

Имейте в виду, что явное приведение оценивается во время выполнения, а не на этапе компиляции. Ради иллюстрации

предположим, что проект
Employees
содержит копию класса
Hexagon
, созданного ранее в главе. Для простоты вы можете добавить в текущий проект такой класс:

class Hexagon

{

public void Draw

{

Console.WriteLine("Drawing a hexagon!");

}

}

Хотя приведение объекта сотрудника к объекту фигуры абсолютно лишено смысла, код вроде показанного ниже скомпилируется без ошибок:

// Привести объект frank к типу Hexagon невозможно,

// но этот код нормально скомпилируется!

object frank = new Manager;

Hexagon hex = (Hexagon)frank;

Тем не менее, вы получите ошибку времени выполнения, или более формально — исключение времени выполнения. В главе 7 будут рассматриваться подробности структурированной обработки исключений, а пока полезно отметить, что при явном приведении можно перехватывать возможные ошибки с применением ключевых слов

try
и
catch
:

// Перехват возможной ошибки приведения.

object frank = new Manager;

Hexagon hex;

try

{

hex = (Hexagon)frank;

}

catch (InvalidCastException ex)

{

Console.WriteLine(ex.Message);

}

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

System.Object
, среди которых лишь малая толика содержит объекты, совместимые с
Employee
. В этом случае первым делом желательно определить, совместим ли элемент массива с типом
Employee
, и если да, то лишь тогда выполнить приведение.

Для быстрого определения совместимости одного типа с другим во время выполнения в C# предусмотрено ключевое слово

as
. С помощью ключевого слова
as
можно определить совместимость, проверив возвращаемое значение на предмет
null
. Взгляните на следующий код:

// Использование ключевого слова as для проверки совместимости.

object[] things = new object[4];

things[0] = new Hexagon;

things[1] = false;

things[2] = new Manager;

things[3] = "Last thing";

foreach (object item in things)

{

Hexagon h = item as Hexagon;

if (h == null)

{

Console.WriteLine("Item is not a hexagon"); // item - не Hexagon

}

else

{

h.Draw;

Поделиться с друзьями: