关于性能:C#Switch语句:更高效不使用默认值?

C# Switch Statement: More efficient to not use default?

我在Visual Studio中创建了一个C方法,该方法只包含一个switch语句,其中每个case都返回一个值。根据个人习惯,我将类似于以下代码的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
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";
    }

我的问题是:哪个代码的性能更好?上面或下面的代码,还是相同的?为什么?

我假设由于编译器的优化…它们可能是相同的…但我真的不知道。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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";
        }
    }

修订:似乎我应该更具体一点:编译时,效率较低的代码是由一个还是另一个生成的?

我意识到表演上的差异可能是微不足道的…我只是好奇而已。


1
2
3
4
5
6
7
8
9
10
11
12
13
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";
        }

变成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.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

将返回移动到默认情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.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编译器优化了它,或者它最终是等价的。


对于其他情况都无效的情况,最好在开关的基础上始终包含默认情况。

这不是一个效率问题,因为如果点击了前面的一个案例-您的程序将不会检查任何其他案例(它相当于使用if/else if/else-其中final else是默认的)。

希望这有帮助。


与其使用函数和switch语句,不如使用通用字典,其中键为kofaxenvironment,值与从开关返回的值相同。类似:

1
Dictionary<KofaxEnvironment, string>

1
Dictionary<int, string>

我也不会担心性能。正确性应该是您的第一个目标。

但是,如果您坚持使用开关,请使用引发异常的默认值:

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

至于性能,交换机默认值和返回值之间的差异(如果有)可以忽略不计。