Почему оператор C # switch не позволяет использовать typeof / GetType ()? - PullRequest
13 голосов
/ 10 ноября 2009

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

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

Ответы [ 10 ]

19 голосов
/ 10 ноября 2009

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

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

switch (Type.GetTypeCode(myObj.GetType())) {
    case TypeCode.Boolean: ...
    case TypeCode.Char: ...
    case TypeCode.String: ...
    case TypeCode.Object: ...
    default: ...
} 
14 голосов
/ 11 ноября 2009

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

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

13 голосов
/ 10 ноября 2009

Проблема в том, что switch (согласно спецификации) работает только с примитивами (int и т. Д.) И строками. Но да, было бы неплохо иметь соответствие стиля F # .

Из §8.7.2:

switch-label:
   case   constant-expression   :
   default   :

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

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

5 голосов
/ 10 ноября 2009

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1

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

4 голосов
/ 10 ноября 2009

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

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

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

2 голосов
/ 10 ноября 2009

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

2 голосов
/ 10 ноября 2009

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

1 голос
/ 21 мая 2017

В 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;
}
1 голос
/ 10 ноября 2009

Почему бы тебе просто не сыграть?) 1001 *

0 голосов
/ 09 марта 2012

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

Строковое переключение выполняется с использованием «if (.. Equals (..))» в нескольких случаях и словаря во многих случаях. Оба этих подхода определены для всех типов .NET, потому что System.Object имеет виртуальные Equals и GetHashCode.

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

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

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

...