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;
Тем не менее, вы получите ошибку времени выполнения, или более формально — 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();