Is switch语句与此特定代码中的if语句相同

本文关键字:语句 if 代码 switch Is | 更新日期: 2023-09-27 18:28:40

我正在尝试了解一个特定的switch语句是否等效于这个if语句。

if (killstreak == 1) //If killstreak is 1, give one throwing knife and write Mr. Kniferino on screen.
        {
            attacker.GiveWeapon("throwingknife_mp");
            attacker.Call("iprintlnBold", "^2Mr. Kniferino");
            attacker.SetPerk("specialty_scavenger", true, false);
        }
        if (killstreak == 2) //If killstreak is 3, give 10 bullets and write You've received 10 bullets on screen.
        {
            attacker.Call("setweaponammoclip", "iw5_fnfiveseven_mp_tactical", 8);
            attacker.Call("setweaponammostock", "iw5_fnfiveseven_mp_tactical", 0);
            attacker.Call("iprintlnBold", "^2You've received 10 ^1bullets");
        }
        if (killstreak == 3) //If killstreak is 2, give Scavenger and write Scavenger on screen.
        {
            AfterDelay(10, () =>
            attacker.SetPerk("specialty_scavenger", true, true));
            attacker.Call("iprintlnBold", "^4Scavenger");
        }

那么这个if语句和这个switch语句等价吗?

switch (killstreak)
        {
            case 1:
                attacker.GiveWeapon("throwingknife_mp");
                attacker.Call("iprintlnBold", "^2Mr. Kniferino");
                attacker.SetPerk("specialty_scavenger", true, false);
            break;
            case 2:
                attacker.Call("setweaponammoclip", "iw5_fnfiveseven_mp_tactical", 8);
                attacker.Call("setweaponammostock", "iw5_fnfiveseven_mp_tactical", 0);
                attacker.Call("iprintlnBold", "^2You've received 10 ^1bullets");
            break;
            case 3:
                AfterDelay(10, () =>
                attacker.SetPerk("specialty_scavenger", true, true));
                attacker.Call("iprintlnBold", "^4Scavenger");
            break;
        }

如果有什么不清楚的地方,我很乐意再解释一遍。

Is switch语句与此特定代码中的if语句相同

差不多,但不完全。在你的案例中,结果是一样的(所以你可以说它们是实现相同逻辑的不同方式)。不同的是,if语句测试将全部执行,而开关只计算一次,然后分支到适当的情况。

您可以添加else语句以提前终止,但switch语句和if/else链之间仍然存在根本区别。后者为您提供了更大的灵活性,而switch在技术上可以由编译器优化为分支表,并且条件(如果是表达式)只计算一次。

这将是更像一个switch语句,但仍然不完全相同:

if (killstreak == 1)
{
     /* case 1 */
}
else if (killstreak == 2)     // only tested if killstreak != 1
{
     /* case 2 */
}
else if (killstreak == 3)     // only tested if killstreak != 1 and != 2
{
    /* case 3 */
}

但正如我所说,这仍然不完全相同。编译器可以将switch语句转换为与上面的if/else链等效的代码,但它也可以转换为查找表,类似于以下内容:

BranchTable = [CASE1_ADDR, CASE2_ADDR, CASE3_ADDR]
goto BranchTable[killstreak]
CASE1_ADDR:
       /* code for test 1*/
       goto AFTER_SWITCH_ADDR;   
CASE2_ADDR:
       /* code for test 2*/
       goto AFTER_SWITCH_ADDR;   
CASE3_ADDR:
       /* code for test 3*/           
AFTER_SWITCH_ADDR:
       /* code following swtich statement */

在函数上,是的,这是一样的,因为1永远不能等于2或3。killsbreak总是等于其中一个,而不是其他。

但从逻辑上讲,你在这里所做的构建在一个重要方面有所不同。C#中的switch语句与if/else-if/else(默认情况下)相比与if/if/if更相似。break防止控制流在第一次遇到求值为true的情况时进一步传递,而您的每一个if语句都将始终求值。

例如,如果你在构建第二个条件时不小心打错了键:

if (killstreak == 1)
{
    FunctionOne();
}
// should have been 2
if (killstreak == 1)
{
    FunctionTwo();
}

FunctionOne()和FunctionTwo()都会执行,因为这两个条件在逻辑上是相互独立的。一个的结果与下一个是否执行无关。

(编辑:有人指出,在switch语句中根本没有办法有两个相同的大小写。它们需要文字或常量,如果在多个情况下使用相同的值,将无法编译。我已经删除了这一部分。)

在只想执行一部分代码的if块中,一种简单的方法是使用else-if:

if (killstreak == 1)
{
    FunctionOne();
}
else if (killstreak == 1)
{
    FunctionTwo();
}

这将与上面的示例switch语句执行相同——只执行FunctionOne()。您的拼写错误不再导致每次用户获得一次击杀时执行两个单独的击杀操作。

编辑:Namfuak指出了另一种可能性——如果在FunctionOne()中以某种方式增加了killsbreak,当执行到下面的第二个if块时,FunctionTwo()也会执行。

// killstreak is 1
if (killstreak == 1)
{
    // will execute
    FunctionOne(); // increments killstreak
}
// killstreak is 2
if (killstreak == 2)
{
    // will also execute
    FunctionTwo();
}