Verwenden Sie eine andere nach Ausnahme (oder nicht)

9

Betrachten Sie diesen Code:

if (x == 1)
{
  throw "no good; aborting" ;
}

[... more code ...]

Betrachten Sie nun diesen Code:

if (x == 1)
{
  throw "no good; aborting" ;
}
else
{
  [... more code ...]
}

Die beiden Fälle funktionieren genauso. Der erste Fall hat den Vorteil, dass Sie den Rest des Codes nicht in ein "einschließen" müssen else. Die zweite hat den Vorteil, der Praxis zu folgen, explizit eine elsefür jeden zu haben if.

Kann jemand solide Argumente für das eine über das andere liefern?

rlandster
quelle
5
Die Praxis, die Sie zugunsten des Expliziten zitieren, elsescheint falsch zu sein. Sehr oft gibt es einfach nichts in den elseBlock zu legen , es sei denn, Sie biegen sich nach hinten.
Konsistenz? Robustheit angesichts von Codeänderungen zulassen? Lesbarkeit?
Thomas Eding
1
Ehhhh, ich bin nicht so sehr ein Fan der Idee, dass jeder eine ifbraucht else. Der letzte Programmierer, der an unserer Codebasis gearbeitet hat, folgte dem streng (na ja , manchmal ... es ist irgendwie schizophren ). Infolgedessen haben wir viele völlig bedeutungslose else { /* do nothing */ }Blöcke, die den Code
verunreinigen
4
"Ein anderes für jedes Wenn" scheint eine bizarre Proklamation zu sein, die von einem Cloud-Architekten im Namen einer (dummen) Konsistenz herausgegeben wurde. Ich sehe keinen Vorteil darin, dieser Praxis zu folgen, und habe noch nie davon gehört.
Erik Dietrich
Es ist sonst überflüssig. Wenn Sie mit dem .NET-Stack arbeiten, installieren Sie ReSharper und Sie werden daran erinnert, alle redundanten else-Anweisungen zu entfernen.
CodeART

Antworten:

16

Sie sollten nicht hinzufügen , elsenachdem ifZweige , dass Bruchkontrolle fließen bedingungslos , wie diejenigen ein , enthaltend throwoder ein return. Dies würde die Lesbarkeit Ihres Programms verbessern, indem die unnötige Verschachtelungsebene, die durch den elseZweig eingeführt wird, beseitigt wird .

Was mit einem einzigen mehr oder weniger in Ordnung aussieht, throwwird wirklich hässlich, wenn mehrere Würfe hintereinander entfaltet werden:

void myMethod(int arg1, int arg2, int arg3) {
    // This is demonstrably ugly - do not code like that!
    if (!isValid(arg1)) {
        throw new ArgumentException("arg1 is invalid");
    } else {
        if (!isValid(arg2)) {
            throw new ArgumentException("arg2 is invalid");
        } else {
            if (!isValid(arg3)) {
                throw new ArgumentException("arg3 is invalid");
            } else {
                // The useful code starts here
            }
        }
    }
}

Dieses Snippet macht dasselbe, sieht aber viel besser aus:

void myMethod(int arg1, int arg2, int arg3) {
    if (!isValid(arg1)) {
        throw new ArgumentException("arg1 is invalid");
    }
    if (!isValid(arg2)) {
        throw new ArgumentException("arg2 is invalid");
    }
    if (!isValid(arg3)) {
        throw new ArgumentException("arg3 is invalid");
    }
    // The useful code starts here
}
dasblinkenlight
quelle
+1 Richtig. Der zweite OP-Fall zwingt Sie zum sorgfältigen Lesen und hinterlässt dann eine WTF. Aber ... versuchen Sie immer, die Methoden kurz zu machen. Eine Rückkehr in der Mitte einer 200-Zeilen-Methode ist ebenfalls schlecht.
Tulains Córdova
1
Um fair zu sein, wenn Sie nur wiederholte If's verwenden, können Sie dies tun else if.
Guvante
2
@Guvante: Jeder ifTest für eine einzelne Bedingung und behandelt sie, wenn die Bedingung wahr ist, und wenn es keine alternative Sache gibt, die passieren muss, wenn die Bedingung falsch ist, sind else ifs unnötig. In meinem Büro gibt es einen Begriff für Code wie dasblinkenlights erstes Snippet: " Pachinko- Maschinen".
Blrfl
@ Blflfl Pachinko Maschinen hah, perfekte Analogie +1
Jimmy Hoffa
@Blrfl: Ich habe darauf hingewiesen, dass wiederholte Wenns ein schlechtes Beispiel für zu viel Verschachtelung sind. Sie sollten ohnehin nicht wiederholt verschachteln, wenn. Ich bin damit einverstanden, dass es im Allgemeinen keinen Grund gibt, dies aufzunehmen, es sei denn, Sie sprechen über eine geringe Menge an Code else.
Guvante
5

Ich würde die "explizite else" -Praxis, die Sie als Anti-Pattern bezeichnen, nennen, da sie die Tatsache verdeckt, dass es keinen Sonderfallcode als else für Ihr if gibt.

Die Lesbarkeit / Wartbarkeit wird im Allgemeinen verbessert, wenn Sie meist nur die erforderlichen Code-Flow-Konstrukte haben und diese minimieren. Dies bedeutet redundante andere und wenn es eine ganze Funktion um einen Bereich erweitert, wird es schwieriger, sie zu verfolgen und zu warten.

Angenommen, Sie haben diese Funktion:

public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
    if (_validColors.Contains(oblogonToConfigure.Color))
    {
        oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
    }
    else
    {
        oblogonToConfigure.Color = _validColors[0];
        oblogonToConfigure.ColorIndex = 0;
    }
}

Jetzt besteht die Anforderung darin, dass Sie während der Konfiguration auch den Typ / Typ-Index des Oblogons angeben sollten. Es gibt mehrere Bereiche, in denen jemand diesen Code platzieren und mit ungültigem Code enden könnte, d. H.

public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
    if (!_validOblogons.Contains(oblogonToConfigure.Type))
    {
        oblogonToConfigure.Type = _validOblogons[0];
        oblogonToConfigure.TypeIndex = 0;
        if (_validColors.Contains(oblogonToConfigure.Color))
        {
            oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
        }
        else
        {
            oblogonToConfigure.Color = _validColors[0];
            oblogonToConfigure.ColorIndex = 0;
        }
    }
    else
    {
        oblogonToConfigure.TypeIndex = _validOblogons.IndexOf(oblogonToConfigure.Type);
    }
}

Vergleichen Sie dies damit, ob der ursprüngliche Code mit minimalen erforderlichen und minimierten Kontrollflusskonstrukten geschrieben wurde.

public void ConfigureOblogon(Oblogon oblogonToConfigure)
{
    if (!_validColors.Contains(oblogonToConfigure.Color))
    {
        oblogonToConfigure.Color = _validColors[0];
    }

    oblogonToConfigure.ColorIndex = _validColors.IndexOf(oblogonToConfigure.Color);
}

Es wäre jetzt weitaus schwieriger, versehentlich etwas in den falschen Bereich zu bringen oder Bereiche aufzublähen, die zu einer Verdoppelung des langfristigen Wachstums und der Aufrechterhaltung dieser Funktion führen. Außerdem ist es offensichtlich, welche möglichen Flüsse durch diese Funktion fließen, sodass die Lesbarkeit verbessert wird.

Ich weiß, das Beispiel ist ein bisschen erfunden, aber ich habe es schon oft gesehen

SomeFunction()
{
    if (isvalid)
    {
        /* ENTIRE FUNCTION */
    }
    /* Nothing should go here but something does on accident, and an invalid scenario is created. */
}

Die Formalisierung dieser Regeln über Kontrollflusskonstrukte kann den Leuten helfen, die Intuition zu entwickeln, die notwendig ist, um etwas zu riechen, wenn sie anfangen, solchen Code zu schreiben. Dann werden sie anfangen zu schreiben ..

SomeFunction()
{
    if (!isvalid)
    {
        /* Nothing should go here, and it's so small no one will likely accidentally put something here */
        return;
    }

    /* ENTIRE FUNCTION */
}
Jimmy Hoffa
quelle