Есть ли существенная разница между использованием if / else и switch-case в C #? - PullRequest
198 голосов
/ 28 декабря 2008

В чем польза / недостаток использования оператора switch по сравнению с if/else в C #. Я не могу представить, что есть такая большая разница, кроме, может быть, внешний вид вашего кода.

Есть ли какая-либо причина, по которой результирующая производительность IL или связанная с ней производительность во время выполнения будут радикально отличаться?

Связанный: Что быстрее, включить строку или еще тип?

Ответы [ 20 ]

304 голосов
/ 28 декабря 2008

Оператор SWITCH производит только ту же сборку, что и IF в режиме отладки или совместимости. В выпуске он будет скомпилирован в таблицу переходов (через оператор MSIL 'switch') - это O (1).

C # (в отличие от многих других языков) также позволяет включать строковые константы - и это работает немного по-другому. Очевидно, что создавать таблицы переходов для строк произвольной длины непрактично, поэтому чаще всего такой переключатель будет скомпилирован в стек IF.

Но если число условий достаточно велико, чтобы покрыть накладные расходы, компилятор C # создаст объект HashTable, заполнит его строковыми константами и выполнит поиск по этой таблице, а затем выполнит переход. Поиск Hashtable не является строго O (1) и имеет заметные постоянные затраты, но если количество меток case велико, это будет значительно быстрее, чем сравнение с каждой строковой константой в IF.

Подводя итог, если количество условий больше 5 или около того, предпочитайте SWITCH, а не IF, в противном случае используйте то, что выглядит лучше.

48 голосов
/ 28 декабря 2008

В целом (с учетом всех языков и всех компиляторов) оператор switch МОЖЕТ СОДЕРЖАТЬ, когда оператор if / else, потому что компилятору легко генерировать таблицы переходов из операторов switch. То же самое можно сделать для операторов if / else с учетом соответствующих ограничений, но это гораздо сложнее.

В случае C # это также верно, но по другим причинам.

С большим количеством строк, есть существенное преимущество в производительности при использовании оператора switch, потому что компилятор будет использовать хеш-таблицу для реализации перехода.

При небольшом количестве строк производительность между ними одинакова.

Это потому, что в этом случае компилятор C # не генерирует таблицу переходов. Вместо этого он генерирует MSIL, который эквивалентен блокам IF / ELSE.

Существует инструкция MSIL «оператор переключения», которая при соединении будет использовать таблицу переходов для реализации оператора переключения. Однако он работает только с целочисленными типами (этот вопрос касается строк).

Для небольшого числа строк компилятору эффективнее генерировать блоки IF / ELSE, чем использовать хеш-таблицу.

Когда я первоначально заметил это, я сделал предположение, что поскольку блоки IF / ELSE использовались с небольшим количеством строк, компилятор сделал то же преобразование для большого числа строк.

Это было НЕПРАВИЛЬНО. «IMA» был достаточно любезен, чтобы указать мне на это (ну ... он не был добр к этому, но он был прав, а я был неправ, что является важной частью)

Я также сделал предположение о том, что в MSIL отсутствует инструкция «switch» (я подумал, что если есть примитив switch, почему они не используют его с хеш-таблицей, поэтому не должно быть переключи примитив ....). Это было неправильно и невероятно глупо с моей стороны. И снова «ИМА» указал мне на это.

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

Тем не менее, я сделал это вики-сообществом, потому что полагаю, что не заслуживаю REP за то, что ошибался Если у вас есть шанс, пожалуйста, проголосуйте за пост Има.

17 голосов
/ 28 декабря 2008

Три причины предпочитать switch:

  • Компилятор, нацеленный на собственный код, часто может скомпилировать оператор switch в одну условную ветвь плюс косвенный переход , тогда как для последовательности if s требуется последовательность условных ветвей . В зависимости от плотности дел было написано очень много научных статей о том, как эффективно составлять описания дел; некоторые связаны со страницей компилятора lcc . (У Lcc был один из самых инновационных компиляторов для коммутаторов.)

  • Оператор switch - это выбор из взаимоисключающих альтернатив , а синтаксис переключателя делает этот поток управления более прозрачным для программиста , чем гнездо if-then-else заявления.

  • В некоторых языках, включая, безусловно, ML и Haskell, компилятор проверяет, не исключены ли какие-либо случаи . Я рассматриваю эту функцию как одно из главных преимуществ ML и Haskell. Я не знаю, может ли C # сделать это.

Анекдот: на лекции, которую он дал, получив награду за пожизненные достижения, я услышал, как Тони Хоар сказал, что из всего, что он делал в своей карьере, было три, которыми он больше всего гордился:

  • Изобретая быструю сортировку
  • Изобретая оператор switch (который Тони назвал оператором case)
  • Начало и окончание карьеры в промышленности

Я не могу представить себе жизнь без switch.

14 голосов
/ 28 декабря 2008

Компилятор собирается оптимизировать практически все в один и тот же код с небольшими отличиями (Кнут, кто-нибудь?)

Разница в том, что оператор switch более чист, чем пятнадцать, если операторы else связаны друг с другом.

Друзья не позволяют друзьям составлять операторы if-else.

14 голосов
/ 28 декабря 2008

На самом деле, оператор switch более эффективен. Компилятор оптимизирует его до таблицы поиска, где с помощью операторов if / else он не может. Недостатком является то, что оператор switch нельзя использовать со значениями переменных.
Вы не можете сделать:

switch(variable)
{
   case someVariable
   break;
   default:
   break;
}

должно быть

switch(variable)
{
  case CONSTANT_VALUE;
  break;
  default:
  break;
}
12 голосов
/ 16 октября 2009

Я не видел, чтобы кто-то еще поднимал (очевидное?) Замечание о том, что предполагаемое преимущество в эффективности оператора switch зависит от того, насколько разные случаи примерно одинаково вероятны. В тех случаях, когда одно (или несколько) значений гораздо более вероятны, лестница if-then-else может быть намного быстрее, гарантируя, что сначала проверяются самые распространенные случаи:

Так, например:

if (x==0) then {
  // do one thing
} else if (x==1) {
  // do the other thing
} else if (x==2) {
  // do the third thing
}

против

switch(x) {
  case 0: 
         // do one thing
         break;
  case 1: 
         // do the other thing
         break;
  case 2: 
         // do the third thing
         break;
}

Если x равен нулю 90% времени, код if-else может быть в два раза быстрее кода на основе коммутатора. Даже если компилятор превратит «переключатель» в какое-то умное движение на основе таблиц, это все равно будет не так быстро, как простая проверка на ноль.

7 голосов
/ 28 декабря 2008

часто это будет выглядеть лучше - то есть будет легче понять, что происходит. Учитывая, что выигрыш в производительности будет в лучшем случае крайне минимальным, наиболее важным отличием является представление кода.

Итак, если if / else выглядит лучше, используйте его, в противном случае используйте оператор switch.

4 голосов
/ 28 декабря 2008

Дополнительная тема, но я часто беспокоюсь (и чаще вижу), что операторы if / else и switch становятся слишком большими со слишком большим количеством случаев. Они часто ухудшают ремонтопригодность.

Общие виновники включают в себя:

  1. Слишком много внутри нескольких операторов if
  2. Больше случаев, чем можно по-человечески проанализировать
  3. Слишком много условий в оценке if, чтобы знать, что ищется

Исправить:

  1. Извлечение в метод рефакторинга.
  2. Используйте словарь с указателями методов вместо регистра или используйте IoC для дополнительной настраиваемости. Методы фабрики также могут быть полезны.
  3. Извлеките условия своим методом
3 голосов
/ 31 июля 2010

Если вы просто используете оператор if или else, базовое решение использует сравнение? оператор

(value == value1) ? (type1)do this : (type1)or do this;

Вы можете выполнить или подпрограмму в переключателе

switch(typeCode)
{
   case TypeCode:Int32:
   case TypeCode.Int64:
     //dosomething here
     break;
   default: return;
}
2 голосов
/ 16 октября 2009

Оператор switch определенно быстрее, чем if if if if. Есть скоростные испытания, которые были поставлены на него BlackWasp

http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx

- Проверьте это

Но сильно зависит от возможностей, которые вы пытаетесь объяснить, но я стараюсь использовать оператор switch всякий раз, когда это возможно.

...