Wie schreibst du Code, dessen Logik vor zukünftigen zusätzlichen Aufzählungen geschützt ist?

Es fällt mir schwer, dieses Problem zu beschreiben. Vielleicht fällt es mir deshalb schwer, eine gute Lösung zu finden (die Worte kooperieren einfach nicht). Lassen Sie mich per Code erklären:

// original code
enum Fruit
{ 
    Apple,
    Orange,
    Banana,
}

...

Fruit fruit = acquireFruit();
if (fruit != Fruit.Orange && fruit != Fruit.Banana)
    coreFruit();
else
    pealFruit();
eatFruit();

Now so tun, als würden Jahre der Entwicklung mit diesen drei Typen vergehen. Verschiedene Varianten der obigen Logik breiten sich in gespeicherten Prozeduren, SSIS-Paketen, Windows-Apps, Web-Apps, Java-Apps, Perl-Skripten usw. au

Schließlich

// new code
enum Fruit
{ 
    Apple,
    Orange,
    Banana,
    Grape,
}

Die meiste Zeit läuft das "System" einwandfrei, bis Trauben verwendet werden. Dann verhalten sich Teile des Systems unangemessen und schälen und / oder entkernen Trauben, wenn dies nicht benötigt oder gewünscht wird.

Welche Richtlinien halten Sie ein, damit diese Unordnung vermieden wird? Ich bevorzuge, dass alter Code eine Ausnahme auslöst, wenn er nicht überarbeitet wurde, um neue Aufzählungen zu berücksichtigen.

Ich habe mir einen Schuss im Dunkeln ausgedacht:

# 1 Vermeiden Sie "Nicht in Logik" wie dieses

// select fruit that needs to be cored
select Fruit from FruitBasket where FruitType not in(Orange, Banana)

# 2 Verwenden Sie bei Bedarf sorgfältig konstruierte NotIn () - Methoden.

internal static class EnumSafetyExtensions
{
    /* By adding enums to these methods, you certify that 1.) ALL the logic inside this assembly is aware of the
     * new enum value and 2.) ALL the new scenarios introduced with this new enum have been accounted for.
     * Adding new enums to an IsNot() method without without carefully examining every reference will result in failure. */

    public static bool IsNot(this SalesOrderType target, params SalesOrderType[] setb)
    {
        // SetA = known values - SetB

        List<SalesOrderType> seta = new List<SalesOrderType>
        {
            SalesOrderType.Allowance,
            SalesOrderType.NonAllowance,
            SalesOrderType.CompanyOrder,
            SalesOrderType.PersonalPurchase,
            SalesOrderType.Allotment,
        };
        setb.ForEach(o => seta.Remove(o));

        // if target is in SetA, target is not in SetB
        if (seta.Contains(target))
            return true;

        // if target is in SetB, target is not not in SetB
        if (setb.Contains(target))
            return false;
        // if the target is not in seta (the considered values minus the query values) and the target isn't in setb
        // (the query values), then we've got a problem.  We've encountered a value that this assembly does not support.

        throw new InvalidOperationException("Unconsidered Value detected: SalesOrderType." + target.ToString());
    }
}

Nun, ich kann sicher Code wie diesen verwenden:

bool needsCoring = fruit.IsNot(Fruit.Orange, Fruit.Banana);

Wenn dieser Code im gesamten System verbreitet wird, werden Ausnahmen geworfen, wenn die Traube in die Stadt rollt (qa wird sie alle fangen).

Das ist sowieso der plan. Das Problem scheint sehr häufig zu sein, aber ich kann auf Google nichts finden (wahrscheinlich meine eigene Schuld).

Wie geht ihr alle damit um?

AKTUALISIEREN

Ich bin der Meinung, dass die Antwort auf dieses Problem darin besteht, einen Mechanismus zu erstellen, der die Verarbeitung stoppt und Tester und Entwickler auf die Tatsache hinweist, dass die neue Aufzählung berücksichtigt werden muss. "switch ... default" ist großartig, wenn Sie es haben.

Wenn C # hat nicht have switch ... Standardmäßig könnten wir den obigen Code wie folgt korrigieren:

Fruit fruit = acquireFruit();
if (fruit != Fruit.Orange && fruit != Fruit.Banana)
    coreFruit();
else if(fruit == Fruit.Apple)
    pealFruit();
else
    throw new NotSupportedException("Unknown Fruit:" + fruit)
eatFruit();

HAFTUNGSAUSSCHLUSS

Du solltest wirklich keinen der oben genannten Pseudocodes verwenden. Es kann (?) Kompilieren oder sogar funktionieren, aber es ist wirklich schrecklicher Code. Ich habe in diesem Thread viele nette Lösungen gesehen, wenn Sie nach einem OOP-basierten Ansatz suchen. Eine gute Lösung besteht natürlich darin, das gesamte Umschalten und Überprüfen in einer zentralen Methode durchzuführen (eine Fabrikmethode ist das, was mir auffällt). Darüber hinaus ist eine Überprüfung des Peer-Codes erforderlich.

Antworten auf die Frage(20)

Ihre Antwort auf die Frage