web-dev-qa-db-fra.com

Si condition à l'intérieur du boîtier de l'interrupteur

J'essaie de convertir une instruction if pour changer de cas (pour la lisibilité) 

1) J'ai lu les déclarations de commutateur qui sont géniales - Est-ce vrai? https://stackoverflow.com/questions/6097513/switch-statement-inside-a-switch-statement-c

2) La déclaration va comme ceci:

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

L'erreur est: 

Le contrôle ne peut pas tomber d'une étiquette de cas ('cas 1:') à une autre

Ceci est la déclaration originale de if:

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

Le compilateur ne comprendra pas ce que vous voulez dire ici.

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

Le compilateur ne reliera pas les points et ne comprendra pas que l'instruction break; dans votre instruction if est liée à l'instruction switch. Au lieu de cela, il essaiera de le lier à une boucle, étant donné que les instructions break; ne peuvent être utilisées qu'avec des boucles, pour en sortir.

Cela signifie que votre bloc case ne possède pas son instruction break pour le compléter et le compilateur se plaint.

Au lieu d'essayer d'extraire le code nécessaire d'une instruction switch, je décomposerais plutôt votre instruction if originale.

Ceci est à toi:

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

Voici comment je l'écrirais:

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

Vous n'avez pas (avez} _ pour emballer tout sur une seule ligne.

De plus, j'essayerais de nommer les propriétés pour qu'elles soient plus faciles à lire. Je renommerais la propriété EXPENSE en IsExpense pour que le code ci-dessus se lise comme suit:

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

Ensuite, idéalement, je reformulerais les sous-expressions en méthodes:

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;
}

Ensuite, vous pouvez replacer l'expression dans l'instruction if:

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

Cela devrait être plus facile à lire et à changer plus tard.

Tout d'abord, j'ai remarqué que vous avez oublié de poser une question dans votre deuxième point. Je vais donc vous poser quelques questions concernant votre deuxième point:

Quelle est la signification de l'erreur "ne peut pas tomber à travers"?

Contrairement à C et C++, C # ne permet pas de passer accidentellement d'une section de commutateur à une autre. Chaque section de commutation doit avoir un "point final inaccessible"; il devrait se terminer par une pause, aller, revenir, lancer ou (rarement) boucle infinie. 

Cela empêche le bug commun d'oubli de mettre dans la pause et de "tomber à travers" accidentellement.

Vous avez écrit votre code comme si le dépassement était légal; Je suppose que vous êtes un programmeur C.

Comment puis-je forcer la chute en C #?

Comme ça:

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;
}

Maintenant, l'analyseur d'accessibilité peut déterminer que, quelle que soit la branche du "si" utilisée, l'extrémité de la section de commutation est inaccessible.

Est-ce que c'est bon style?

Non, votre code original était beaucoup plus lisible.

J'ai lu les déclarations de commutateur sont nauséabondes en général - Est-ce vrai? 

Les opinions varient. Les instructions Switch sont très utiles lorsqu'il existe un petit nombre d'alternatives très "nettes" dont les comportements n'interagissent pas de manière complexe. Certaines personnes vous diront que la logique commutée devrait plutôt être gérée par des méthodes virtuelles ou par des modèles de visiteurs, mais cela peut aussi être abusé. 

Devrais-je utiliser un commutateur dans ce cas particulier?

Je ne voudrais pas 

Comment amélioreriez-vous mon code?

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

Tout d'abord, ne nommez PAS les choses EN TOUT CAPS en C #.

Deuxièmement, ne comparez pas les valeurs booléennes aux valeurs true et false. Ils sont déjà des booléens! Si vous voulez connaître la vérité de la déclaration X, vous ne diriez pas en anglais "est-il vrai que X est vrai?" Vous diriez "X est-il vrai?" 

J'écrirais probablement:

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

Ou, mieux encore, je résumerais le test en une méthode à part:

if (canDisplayExpenses())
{ 
    //Code
}

Ou résumez le tout:

DisplayExpenses();
12
Eric Lippert

Utilisez les instructions if et extrayez des conditions complexes dans des méthodes, par exemple

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

Rappelez-vous de OOP et du polymorphisme à chaque fois que vous écrivez un tel 'commutateur', en ajoutant un autre case à ce code sera un cauchemar

voir les instructions this et similaire (C++) concernant la conversion de commutateurs

PS si vous souhaitez rendre votre code propre et lisible, envisagez de lire Smalltalk Best Practice Patterns de Kent Beck et/ou Clean Code de Uncle Bob vraiment apprécié les deux, je le recommande vivement.

5

Si vous voulez lisibilité , jetez simplement votre corbeille de syntaxe:

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

Fournissez la partie else pour chacun d’entre eux afin qu’elle ne génère pas d’erreur. Cependant, comme d’autres le disent, vous n’avez pas besoin de switch dans ce cas.

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;
}
2

La raison pour laquelle vous obtenez cette erreur est que vous ne définissez pas d'instructions break.

Vous avez défini la break conditionnellement. 

            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:
                    ...
            }

Assurez-vous que chaque instruction de cas a sa propre variable break ou regroupez-les comme suit.

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

Refacturez les déclarations if pour pouvoir les exprimer comme suit:

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

La logique extraite:

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

D'accord avec Dennis, vous ne voulez pas d'un commutateur pour résoudre ce problème.

Bien que probablement moins lisible, vous pouvez aussi utiliser plus court:

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