web-dev-qa-db-ja.com

スイッチケース内の状態

If文を変換してケースを切り替えようとしています(読みやすくするため)

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つのケースラベル(「ケース1:」)から別のケースラベルに制御を移すことはできません

これは元のifステートメントです:

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

コンパイラは、ここでの意味を理解しません。

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

コンパイラーはドットを接続せず、ifステートメント内のbreak;ステートメントが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
}

すべてを1行に詰め込むためにhaveを実行する必要はありません。

また、読みやすいようにプロパティに名前を付け、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
}

これは読みやすく、後で変更する必要があります。

まず、2つ目のポイントで質問するのを忘れていることに気づきました。だから私はあなたのためにいくつかの質問をするつもりです。

「通過できません」エラーの意味は何ですか?

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ステートメントを読んだことは全体的に素晴らしいです-それは本当ですか?

意見はさまざまです。 switchステートメントは、動作が複雑な方法で相互作用しない非常に「鮮明な」代替手段が少数ある場合に非常に役立ちます。一部の人々は、スイッチドロジックは代わりに仮想メソッドまたはビジターパターンで処理する必要があると言いますが、それも悪用される可能性があります。

この特定のケースではスイッチを使用する必要がありますか?

私はしません。

私のコードをどのように改善しますか?

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

まず、C#ではすべて大文字で名前を付けないでください。

次に、ブール値をtrueとfalseと比較しないでください。それらはすでにブール値です!ステートメントXの真実を知りたい場合、英語で「Xが真であることは本当ですか?」とは言えません。 「Xは本当ですか?」

私はおそらく書くでしょう:

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

または、さらに良いことに、独自のメソッドにテストを抽象化します。

if (canDisplayExpenses())
{ 
    //Code
}

または全体を抽象化します。

DisplayExpenses();
14
Eric Lippert

Ifステートメントを使用して、複雑な条件をメソッドに抽出します。

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

OOPと、そのような「スイッチ」を書くたびにポリモーフィズムについて覚えておいてください。そのコードに別のケースを追加すると、悪夢になります

スイッチの変換に関する this および similar(C++) の説明を参照してください

PSコードをクリーンで読みやすくすることに興味がある場合Kent BeckによるSmalltalkのベストプラクティスパターン または ncle Bobによるクリーンコード 両方を本当に楽しんだので、強くお勧めします。

5

読みやすさが必要な場合は、構文のゴミを捨ててください:

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

エラーをスローしないように、それぞれに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;
}

このエラーが発生する理由は、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ステートメントを次のようにグループ化します。

            switch (Show)
            {
                case Display.Expense:
                case Display.All:
                    // do stuff
                    // Expense and All have the same behavior
            }
1
bas

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);
}
0
Matthew Watson

デニスに同意します。この問題の切り替えケースは必要ありません。

おそらく読みにくくなりますが、短くすることもできます:

if (Show == Display.All || (expected.EXPENSE == (Show == Display.Expense)))
{
    //Code
}
0
publicgk