Инструкция C # Switch: более эффективно, чтобы не использовать по умолчанию? - PullRequest
9 голосов
/ 28 февраля 2012

Я создавал метод C # в visual studio, который содержал только оператор switch, где каждый случай возвращал значение.По личной привычке я поместил нечто похожее на следующий код:

private string SwitchMethod(int num)
    {
        switch (num)
        {
            case 0:
                return "result 1";
            case 1:
                return "result 2";
            case 2:
                return "result 3";
        }
        return "no result";
    }

Мой вопрос такой: какой код будет иметь лучшую производительность?Код выше или ниже или одинаковый?И почему?

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

private string SwitchMethod(int num)
    {
        switch (num)
        {
            case 0:
                return "result 1";
            case 1:
                return "result 2";
            case 2:
                return "result 3";
            default:
                return "no result";
        }
    }

ПЕРЕСМОТР: Кажется,что я должен быть более конкретным: при компиляции ... будет генерироваться менее эффективный код одним или другим?

Я понимаю, что разница в производительности может быть незначительной ... Мне просто любопытно на самом деле.

Ответы [ 3 ]

11 голосов
/ 28 февраля 2012
public static string foo(int num)
        {
            switch (num)
            {
                case 0:
                    return "result 1";
                case 1:
                    return "result 2";
                case 2:
                    return "result 3";
            }
            return "no result";
        }

становится:

.method public hidebysig static string  foo(int32 num) cil managed
{
  // Code size       57 (0x39)
  .maxstack  1
  .locals init ([0] string CS$1$0000,
           [1] int32 CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  stloc.1
  IL_0003:  ldloc.1
  IL_0004:  switch     ( 
                        IL_0017,
                        IL_001f,
                        IL_0027)
  IL_0015:  br.s       IL_002f
  IL_0017:  ldstr      "result 1"
  IL_001c:  stloc.0
  IL_001d:  br.s       IL_0037
  IL_001f:  ldstr      "result 2"
  IL_0024:  stloc.0
  IL_0025:  br.s       IL_0037
  IL_0027:  ldstr      "result 3"
  IL_002c:  stloc.0
  IL_002d:  br.s       IL_0037
  IL_002f:  ldstr      "no result"
  IL_0034:  stloc.0
  IL_0035:  br.s       IL_0037
  IL_0037:  ldloc.0
  IL_0038:  ret
} // end of method Program::foo

Перемещение возврата в регистр по умолчанию:

.method public hidebysig static string  foo(int32 num) cil managed
{
  // Code size       57 (0x39)
  .maxstack  1
  .locals init ([0] string CS$1$0000,
           [1] int32 CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  stloc.1
  IL_0003:  ldloc.1
  IL_0004:  switch     ( 
                        IL_0017,
                        IL_001f,
                        IL_0027)
  IL_0015:  br.s       IL_002f
  IL_0017:  ldstr      "result 1"
  IL_001c:  stloc.0
  IL_001d:  br.s       IL_0037
  IL_001f:  ldstr      "result 2"
  IL_0024:  stloc.0
  IL_0025:  br.s       IL_0037
  IL_0027:  ldstr      "result 3"
  IL_002c:  stloc.0
  IL_002d:  br.s       IL_0037
  IL_002f:  ldstr      "result 4"
  IL_0034:  stloc.0
  IL_0035:  br.s       IL_0037
  IL_0037:  ldloc.0
  IL_0038:  ret
} // end of method Program::foo

Точно так же. Нет разницы в производительности. Я изменил «без результата» на результат 4, просто чтобы убедиться, что код был восстановлен. Очевидно, компилятор C # оптимизирует его или он просто оказывается эквивалентным.

4 голосов
/ 28 февраля 2012

Рекомендуется всегда включать регистр по умолчанию в основу коммутатора для ситуаций, когда ни один из других случаев не является действительным.

Это не проблема эффективности, потому что, если удастся выполнить один из предыдущих случаев - ваша программа не будет проверять другие случаи (это эквивалентно использованию if / else if / else - где final else является значением по умолчанию).

Надеюсь, это поможет.

3 голосов
/ 28 февраля 2012

Вместо функции и оператора switch вам лучше использовать универсальный словарь, в котором ключом является KofaxEnvironment, а значение совпадает с тем, что вы возвращаете из коммутатора. Что-то вроде:

Dictionary<KofaxEnvironment, string>

или

Dictionary<int, string>

Я бы тоже не беспокоился о производительности. Корректность должна быть вашей первой целью.

Но если вы придерживаетесь переключателя, используйте значение по умолчанию, которое выдает исключение:

default:
    throw new ArgumentException("Serious programmer error!");

А что касается производительности, разница (если она вообще есть) между переключателем по умолчанию и переходом к возврату будет незначительной.

...