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

时间:2014-11-01 21:12:52

标签: c#

我试图了解特定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;
        }

如果事情不明确,我会很高兴再次解释。

2 个答案:

答案 0 :(得分:4)

几乎,但不完全。您案例中的结果将是相同的(因此您可以说它们是实现相同逻辑的不同方式)。不同之处在于,您的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 :(得分:1)

功能上,是的,它是相同的,因为1永远不能等于2或3. killstreak总是等于其中一个而不是其他的。

但从逻辑上讲,你在这里建造的建筑在很大程度上是不同的。 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()。每次用户获得一次杀戮时,您的拼写错误不再导致两个单独的killstreak操作执行。

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

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