Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 91 92 93 94 95 96 97 98 99 ... 407
в цепочке наследования он находится выше, чем 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();

  }

}

Здесь производится проход в цикле по всем элементам в массиве объектов и проверка каждого из них на совместимость с классом Hexagon. Метод Draw() вызывается, если (и только если) обнаруживается объект, совместимый с Hexagon. В противном случае выводится сообщение о том, что элемент несовместим.

Использование ключевого слова is (обновление в версиях 7.0, 9.0)

В дополнение к ключевому слову as язык C# предлагает ключевое слово is, предназначенное для определения совместимости типов двух элементов. Тем не менее, в отличие от ключевого слова as, если типы не совместимы, тогда ключевое слово is возвращает false, а не ссылку null. В текущий момент метод GivePromotion() спроектирован для приема любого возможного типа, производного от Employee. Взгляните на следующую его модификацию, в которой теперь осуществляется проверка, какой конкретно "тип сотрудника" был передан:

static void GivePromotion(Employee emp)

{

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

  if (emp is SalesPerson)

  {

    Console.WriteLine("{0} made {1} sale(s)!", emp.Name,

      ((SalesPerson)emp).SalesNumber);

    Console.WriteLine();

  }

  else if (emp is Manager)

  {

    Console.WriteLine("{0} had {1} stock options...", emp.Name,

      ((Manager)emp).StockOptions);

    Console.WriteLine();

  }

}

Здесь во время выполнения производится проверка с целью выяснения, на что именно в памяти указывает входная ссылка типа базового класса. После определения, принят ли объект типа SalesPerson или Manager, можно применить явное приведение, чтобы получить доступ к специализированным членам данного типа. Также обратите внимание, что помещать операции приведения внутрь конструкции try/catch не обязательно, т.к. внутри раздела if, выполнившего проверку условия, уже известно, что приведение безопасно.

Начиная с версии C# 7.0, с помощью ключевого слова is переменной можно также присваивать объект преобразованного типа, если приведение работает. Это позволяет сделать предыдущий метод более ясным, устраняя проблему "двойного приведения". В предшествующем примере первое приведение выполняется, когда производится проверка совпадения типов, и если она проходит успешно, то переменную придется приводить снова. Взгляните на следующее обновление предыдущего метода:

static void GivePromotion(Employee emp)

{

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

  // Если SalesPerson, тогда присвоить переменной s

  if (emp is SalesPerson s)

  {

    Console.WriteLine("{0} made {1} sale(s)!", s.Name,

      s.SalesNumber);

    Console.WriteLine();

  }

  // Если Manager, тогда присвоить переменной m

  else if (emp is Manager m)

  {

    Console.WriteLine("{0} had {1} stock options...",

      m.Name, m.StockOptions);

    Console.WriteLine();

  }

}

В версии C# 9.0 появились дополнительные возможности сопоставления с образцом (они были раскрыты в главе 3). Такое обновленное сопоставление с образцом можно использовать с ключевым словом is. Например, для проверки, что объект сотрудника не относится ни к классу Manager, ни к классу SalesPerson, применяйте следующий код:

if (emp is not Manager and not SalesPerson)

1 ... 91 92 93 94 95 96 97 98 99 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий