9

我正在尝试将 if 语句转换为 switch 案例(为了便于阅读)

1)我读过 switch 语句一般都很棒 - 这是真的吗? https://stackoverflow.com/questions/6097513/switch-statement-inside-a-switch-statement-c

2)声明如下:

switch (Show)
                {
                    case Display.Expense:
                        if (expected.EXPENSE != true)
                            break;
                    case Display.NonExpense:
                        if (expected.EXPENSE == true)
                            break;
                    case Display.All:
                        //Code
                        break;
                }

错误是:

控制不能从一个案例标签(“案例 1:”)转移到另一个案例标签

这是原始的 if 语句:

if ((Show == Display.All) || (expected.EXPENSE == true && Show == Display.Expense) || (expected.EXPENSE == false && Show == Display.NonExpense))
{
    //Code
}
4

8 回答 8

14

首先,我注意到您在第二点中忘了问一个问题。所以我要问你一些问题来解决你的第二点:

“不能通过”错误是什么意思?

与 C 和 C++ 不同,C# 不允许从一个开关部分意外跌落到另一个开关部分。每个开关段都必须有一个“无法到达的端点”;它应该以 break、goto、return、throw 或(很少)无限循环结束。

这可以防止忘记休息和意外“跌倒”的常见错误。

您已经编写了代码,就好像失败是合法的一样;我的猜测是你是一个 C 程序员。

如何在 C# 中强制失败?

像这样:

switch (Show)
{
case Display.Expense:
    if (expected.EXPENSE != true)
        break;
    else
        goto case Display.All;
case Display.NonExpense:
    if (expected.EXPENSE == true)
        break;
    else  
        goto case Display.All;
case Display.All:
    //Code
    break;
}

现在可达性分析器可以确定无论采用“if”的哪个分支,切换段端点都是不可达的。

这是好风格吗?

不,您的原始代码更具可读性。

我读过 switch 语句一般都很棒 - 这是真的吗?

意见不一。当有少量非常“清晰”的替代方案的行为不以复杂的方式交互时,切换语句非常有用。有些人会告诉你,切换逻辑应该由虚拟方法或访问者模式来处理,但这也可能被滥用。

在这种特殊情况下我应该使用开关吗?

我不会。

您将如何改进我的代码?

if ((Show == Display.All) || 
    (expected.EXPENSE == true && Show == Display.Expense) || 
    (expected.EXPENSE == false && Show == Display.NonExpense))
{
    //Code
}

首先,不要在 C# 中全部大写。

其次,不要将布尔值与真假进行比较。他们已经是布尔值了!如果你想知道陈述 X 的真实性,你不会用英语说“X 是真的吗?” 你会说“X 是真的吗?”

我可能会写:

if (Show == Display.All || 
    Show == Display.Expense && expected.Expense || 
    Show == Display.NonExpense && !expected.Expense)
{
    //Code
}

或者,更好的是,我会将测试抽象为一个自己的方法:

if (canDisplayExpenses())
{ 
    //Code
}

或者把整个事情抽象出来:

DisplayExpenses();
于 2013-04-01T15:19:40.570 回答
8

编译器不会理解你在这里的意思。

switch (Show)
{
    case Display.Expense:
        if (expected.EXPENSE != true)
            break;
        // missing break here
    case Display.NonExpense:

编译器不会连接点并理解您的break;语句if中的语句与语句相关联switch。相反,它会尝试将其链接到一个循环,因为break;它们自己的语句只能与循环一起使用,以摆脱它。

这意味着您的case块缺少break完成它的语句,因此编译器会抱怨。

我不会尝试从switch语句中提取必要的代码,而是分解您的原始if语句。

这是你的:

if ((Show == Display.All) || (expected.EXPENSE == true && Show == Display.Expense) || (expected.EXPENSE == false && Show == Display.NonExpense))
{
    //Code
}

我会这样写:

bool doDisplayExpected =
       (Show == Display.All)
    || (Show == Display.Expense    && expected.EXPENSE)
    || (Show == Display.NonExpense && !expected.EXPENSE);
if (doDisplayExpected)
{
    // code
}

您不必将所有东西打包在一条线上。

另外,我会尝试命名属性,以便它们更易于阅读,我会将EXPENSE属性重命名为,IsExpense以便上面的代码如下所示:

bool doDisplayExpected =
       (Show == Display.All)
    || (Show == Display.Expense    && expected.IsExpense)
    || (Show == Display.NonExpense && !expected.IsExpense);
if (doDisplayExpected)
{
    // code
}

然后,理想情况下,我会将子表达式重构为方法:

bool doDisplayExpected =
       ShowAll()
    || ShowExpense(expected)
    || ShowNonExpense(expected);
if (doDisplayExpected)
{
    // code
}

public bool ShowAll()
{
    return Show == Display.All;
}

public bool ShowExpense(Expected expected)
{
    return Show == Display.Expense && expected.EXPENSE;
}

public bool ShowNonExpense(Expected expected)
{
    return Show == Display.NonExpense && !expected.EXPENSE;
}

然后您可以将表达式放回 if 语句中:

if (ShowAll() || ShowExpense(expected) || ShowNonExpense(expected))
{
    // code
}

这应该更容易阅读,并在以后更改。

于 2013-04-01T11:40:51.240 回答
5

使用 if 语句并将复杂条件提取到方法中,例如

if (ShowAll() || ShowExpense())
{
}

每次编写此类“开关”时请记住 OOP 和多态性,向该代码添加另一个案例将是一场噩梦

请参阅有关转换开关的说明和类似 (C++)说明

PS,如果您有兴趣使您的代码干净易读,请考虑阅读Kent Beck 的 Smalltalk Best Practice Patterns和/或Uncle Bob 的 Clean Code 我真的很喜欢这两本书,强烈推荐。

于 2013-04-01T11:37:19.463 回答
3

如果你想要可读性,只需扔掉你的语法垃圾:

if (Show == Display.All || expected.EXPENSE && Show == Display.Expense || !expected.EXPENSE && Show == Display.NonExpense)
{
    //Code
}
于 2013-04-01T11:34:05.423 回答
2

为他们每个人提供零件,这样它就不会抛出错误,但是正如其他人所说,在这种情况下else你实际上不需要。switch

switch (Show)
{
    case Display.Expense:
         if (expected.EXPENSE != true)
             // do what you want
             break;
         else 
             // do what you want
             break;
    case Display.NonExpense:
         if (expected.EXPENSE == true)
             // do what you want
             break;
         else 
             // do what you want
             break;
    case Display.All:
        //Code
        break;
}
于 2013-04-01T11:33:04.273 回答
1

您收到此错误的原因是您没有定义break语句。

break有条件地定义了。

            switch (Show)
            {
                case Display.Expense:
                    if (expected.EXPENSE != true)
                        break;

                // Note that the break above is in scope of you if statement, and will
                // result in a compiler error
                case Display.NonExpense:
                    ...
            }

要么确保每个 case 语句都有自己break的 case 语句,要么按如下方式对 case 语句进行分组。

            switch (Show)
            {
                case Display.Expense:
                case Display.All:
                    // do stuff
                    // Expense and All have the same behavior
            }
于 2013-04-01T11:43:46.037 回答
0

重构if语句,以便您可以像这样表达它:

if (isDisplayAll() || isExpense(expected) || isNonExpense(expected))
{
    // Code
}

提取的逻辑:

private bool isDisplayAll()
{
    return (Show == Display.All);
}

private bool IsExpense(Expected expected)
{
    return expected.EXPENSE && (Show == Display.Expense);
}


private bool IsNonExpense(Expected expected)
{
    return !expected.EXPENSE && (Show == Display.NonExpense);
}
于 2013-04-01T11:39:32.273 回答
0

同意丹尼斯的观点,你不想要一个开关盒来解决这个问题。

虽然可能不太可读,但您也可以使用更短的:

if (Show == Display.All || (expected.EXPENSE == (Show == Display.Expense)))
{
    //Code
}
于 2013-04-01T11:47:44.853 回答