Почему оператор c# switch не позволяет использовать typeof / GetType()?

как в этом примере:

switch ( myObj.GetType ( ) )
{
    case typeof(MyObject):
        Console.WriteLine ( "MyObject is here" );
        break;
}

10 ответов


проблема в том, что switch (в спецификации) работает только с примитивами (int etc) и строками. Но да, было бы неплохо!--4-->чтобы иметь соответствие F#-style.

из §8.7.2:

switch-label:
   case   constant-expression   :
   default   :

... Управляющий тип оператора switch устанавливается выражением switch. Если тип выражения коммутатора-sbyte, byte, short, ushort, int, uint, long, ulong, char, string или enum-тип, тогда это управляющий тип переключатель заявление. В противном случае должно существовать ровно одно пользовательское неявное преобразование (§6.4) из тип выражения switch для одного из следующих возможных управляющих типов: тип sbyte, байт, короткие, ushort, int и uint, не долго, как ulong, char, в строку. Если нет такого неявного преобразование существует, или если существует несколько таких неявных преобразований, время компиляции возникает ошибка.

очевидно, однако, что работа с таким ограниченным набором позволяет просто (и эффективный) Ил. Обратите внимание, что string обрабатывается через сопоставление словаря с целым числом.


второй на посту Питера Халлама; это отличное объяснение.

вы можете использовать TypeCode для работы с простыми типами,.

switch (Type.GetTypeCode(myObj.GetType())) {
    case TypeCode.Boolean: ...
    case TypeCode.Char: ...
    case TypeCode.String: ...
    case TypeCode.Object: ...
    default: ...
} 

Я бы добавил к превосходному анализу Питера следующую мысль:

Fundamenatally, цель "переключатель" -выбрать одну из нескольких различных возможностей. Заданное значение типа enum, integer, Boolean или string может быть только одним значением, поэтому имеет смысл "переключаться" на такое значение. Но типы принципиально различны. Данное значение обычно имеет много типы. Типы часто перекрытие. Предлагаемый " переключатель типа" не соответствует заявленному цель из конструкции switch.


здесь хороший пост в блоге на MSDN от Peter Hallam что объясняет проблемы включения непостоянных значений.

" порядок меток корпуса становится значимый при определении, какой блок кода выполняется. Потому что выражения меток case не являются константа компилятор не может проверить что значения меток case отличный, так что это возможность что должно быть удовлетворено. Это работает счетчик к большинству интуиция программистов о инструкции switch в паре путей. Большинство программистов удивлен, узнав, что изменение порядок их блоков case изменил смысл их программы. Повернуть его вокруг, было бы удивительно, если выражение при включении было равно к выражению в метке case, но контроль не пошел на этот ярлык."


вы могли бы сделать

switch ( myObj.GetType().Name )
{
    case "MyObject":
        Console.WriteLine ( "MyObject is here" );
        break;
}

это работает, потому что переключение работает только на примитивных типах (как говорили другие).


Это то, что typeof не является константой, и случаи должны быть константами.


переключатель в C# работает только для интегралов или строк. myObj.GetType () возвращает тип, который не является ни интегралом, ни строкой.


Почему бы вам просто не tostring ()?


В C# 7.0 вы можете сделать это. Видеть сопоставление шаблонов в блоках корпуса C# 7.0

// ----- Assume that spaceItem is of type SpaceType,
//       and that Planet and Star derive from SpaceType.
switch (spaceItem)
{
  case Planet p:
    if (p.Type != PlanetType.GasGiant)
      LandSpacecraft(p);
    break;
  case Star s:
    AvoidHeatSource(s);
    break;
  case null:
    // ----- If spaceItem is null, processing falls here,
    //       even if it is a Planet or Star null instance.
    break;
  default:
    // ----- Anything else that is not Planet, Star, or null.
    break;
}

нет никаких веских причин для MS не реализовывать переключение типов, кроме лени.

переключение строк выполняется с помощью " if(..Равняется.(.)) "s с несколькими случаями и словарем со многими случаями. Оба этих подхода определены для всех типов .NET, потому что System.Объект Equals и GetHashCode, которые являются виртуальными.

можно сказать ,что "switch может использовать выражение любого типа, где Equals и GetHashCode переопределяются", что автоматически квалифицирует строку, тип и т. д. Да, плохая реализация Equals/GetHashCode нарушит оператор switch, но эй, вы также можете сломать оператор"==", цикл "foreach" и кучу других вещей, поэтому я действительно не вижу "большой проблемы" с коммутатором, нарушенным ошибкой программиста. Но даже если они не хотят разрешать это для всех типов, по какой-то причине, конечно, тип безопасен, потому что тип.Equals () хорошо определен, и GetHashCode также реализован.

кроме того, я не купите аргумент, который вы считаете наследованием; переключатель переходит к случаю, константа которого (и тип (int) является константой, не ошибитесь в этом) равна выражению - наследование-это еще одно "поведение" типа Type. Даже не нужно рассматривать наследование, я имею в виду, мы отказываемся сравнивать 2 объекта только потому, что у них есть другие качества? Нет, не знаем, потому что равенство всегда определено. В принципе, дело в том, что нет перекрытия между различными типами.

Так как я уже сказал, Есть только одна причина: лень. :)