我有以下相当简单的 switch 语句。 //早些时候 字符串 fullPath = GetFullPath(); 字符串类型 = GetEntityType();
switch (type.ToLower()) {
case "tables":
tables.Add(fullPath);
break;
case "views":
views.Add(fullPath);
break;
case "functions":
functions.Add(fullPath);
break;
case "storedprocs":
storedprocs.Add(fullPath);
break;
case "data":
data.Add(fullPath);
break;
case "layouts":
layouts.Add(fullPath);
break;
case "scripts":
scripts.Add(fullPath);
break;
default:
Console.WriteLine($"What is this: {type}");
break;
}
当我使用 Reflector 反编译生成的二进制文件时,switch(string)
已更改为 ComputeStringHash,然后在每个 case 语句中它通过 if
语句检查值.听起来它做了双倍的工作。
string s = str2.ToLower();
switch (<PrivateImplementationDetails>.ComputeStringHash(s))
{
case 0x20890fc4:
if (s == "tables")
{
break;
}
goto Label_0218;
case 0x454a414e:
if (s == "functions")
{
goto Label_01DE;
}
goto Label_0218;
case 0x4facf6d1:
if (s == "views")
{
goto Label_01D3;
}
goto Label_0218;
case 0xcdfe2cb3:
if (s == "storedprocs")
{
goto Label_01E9;
}
goto Label_0218;
case 0xd872e2a5:
if (s == "data")
{
goto Label_01F4;
}
goto Label_0218;
case 0x9b4a129b:
if (s == "scripts")
{
goto Label_020C;
}
goto Label_0218;
case 0xba971064:
if (s == "layouts")
{
goto Label_0200;
}
goto Label_0218;
default:
goto Label_0218;
}
first.Add(fullPath);
continue;
Label_01D3:
second.Add(fullPath);
continue;
Label_01DE:
list3.Add(fullPath);
continue;
Label_01E9:
list4.Add(fullPath);
continue;
Label_01F4:
list5.Add(fullPath);
continue;
Label_0200:
list6.Add(fullPath);
continue;
Label_020C:
list7.Add(fullPath);
continue;
Label_0218:
Console.WriteLine("What is this: " + str2);
}
最佳答案
这是一个非常聪明的优化,它让 switch
及时完成它的工作,几乎与语句的 case
block 中的字符串数量无关。
此优化基于相同字符串的哈希码必须相同的观察结果。编译器不是逐一检查字符串是否相等,而是一次计算目标字符串的散列,然后在 O(1) 中执行基于表的查找。这使编译器达到所需的情况,此时编译器需要检查字符串是否实际上相等。
请注意,在极少数情况下,多个查找字符串会具有相同的哈希码。在这种情况下,生成的 case
语句将包含多个 if
来决定具有相同哈希码的字符串。
总的来说,这种行为模仿了基于散列的字典的行为:散列码决定了case
(相当于一个散列桶)和里面的一系列if
确定是否存在匹配项。这会带来更好的性能,因为它让编译器跳过不必要的检查。
关于c# - 为什么编译器要在开关中添加语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53839624/