2008-12-06 8 views
8

Wir hatten eine Debatte, ob enums nicht initialisierte Werte haben sollten. Beispielsweise. Wir habenSollten enums nicht initialisierte Werte haben.

public enum TimeOfDayType 
{ 
    Morning 
    Afternoon 
    Evening 
} 

oder

public enum TimeOfDayType 
{ 
    None 
    Morning 
    Afternoon 
    Evening 
} 

Ich denke, dass es keine keine sein sollte, aber dann muss man bis zu einem gewissen gültigen Wert bei der Initialisierung auf Default. Aber andere dachten, dass es einen Hinweis auf den unitize Status geben sollte, indem sie eine andere enum haben, die None oder NotSet ist.

Gedanken?

Antwort

13

Apropos Nullable-Typen - ich denke, sie können verwendet werden, um das Problem zu lösen, die Initialisierung eines Enums zu erzwingen/nicht zu erzwingen. Sagen wir

enum Color { Red, Blue } 

haben Und lassen Sie uns sagen, dass Sie eine Funktion haben:

void Draw(Color c); 

Diese Funktion sagt, dass es eine gültige Color erfordert. Allerdings konnten wir auch diese Funktion haben:

void Draw(Color? c); 

, die besagt, dass die Funktion nicht eine Farbe weitergegeben werden handhaben kann (null weitergegeben würden, um „do not care“).

Nun, es ist eine Alternative zu None Mitglieder.

+0

Einverstanden, die sauberste Lösung ist ein Nullable-Typ. Es wird auch gut auf DB-Schemata abgebildet. –

+9

Es ist bedauerlich, dass enums in .NET Sie nicht zwingen, einen gültigen Wert überhaupt zu übergeben. Ich könnte (Farbe) 123123 übergeben, die kompilieren würde und gut funktionieren würde - die Draw-Methode müsste die Validierung durchführen :( –

+2

Wahrscheinlich eine Vererbung von C, wo der Compiler nicht weiß, ob eine Enumeration als eine echte Enumeration verwendet wird Typ oder als eine Reihe von Flags. So wirft es seine Hände in die Luft und ergibt sich. –

1

Hängt davon ab, wie der Typ verwendet wird. Es ist oft einfacher für Benutzer des Typs, keinen "undefinierten" Wert zu haben, da Sie keinen speziellen Wert angeben müssen. Aber wenn Sie eine benötigen (weil Werte manchmal in einem Zustand sein müssen, der sonst keiner der aufgezählten Werte ist), dann brauchen Sie einen. Normalerweise speichern Sie keinen Sonderfallcode, indem Sie zwei Enums anstelle von einem verwenden.

Es ist ein bisschen wie fragen, ob Sie Nullable-Typen verwenden sollten.

3

Nur hinzufügen, um Franks Antwort, eines der einzigen Male, die ich für ein 'None' Element in einem Enum über Nullable entscheiden würde, wenn die Enum als Flags verwendet wird. Das Element "None" würde eine ID von 0 haben.

4

In einigen der vorherigen Antworten wurde ein Nullwert-Enum als Lösung vorgeschlagen. Eine Nullable-Enumeration hat jedoch den Nachteil, dass Clients bei jedem Aufruf der Enumeration nach einem Nullwert suchen müssen. Wenn Sie dagegen den Standardwert "None" haben, können Sie einen Schalter für die sinnvollen Werte verwenden und einfach "None" ignorieren, ohne befürchten zu müssen, dass die enum-Variable null sein könnte.

Wie auch immer, ich denke, einen Standardwert von "None" oder Enum Nullable macht nur Sinn, wenn die Enumeration als Argument in einem Standardkonstruktor für eine Klasse verwendet wird. Und Sie müssen sich selbst fragen - sollten die Objekte dieser Klasse keinen sinnvollen Standardwert haben? Verwenden Sie Ihr Beispiel mit der TimeOfDayType-Enumeration - wenn Sie ein Objekt mit TimeOfDayType.None initialisieren, können Sie es sowieso nicht verwenden, bevor Sie den Wert in Morning, Afternoon oder Evening ändern. Könntest du nicht sagen, dass der Standard Morning statt None ist? Oder - was noch besser ist - könnten Sie Ihre Objekte nicht erstellen, nachdem Sie bereits wissen, welchen Aufzählungswert sie benötigen? Ich denke, wenn das Problem in den frühen Entwurfsphasen richtig angegangen wird, sollten Sie keinen speziellen Standardwert für Ihre Enums benötigen.

Natürlich ist das alles eine Verallgemeinerung.Vielleicht kann es nicht auf Ihr spezielles Szenario angewendet werden. Wenn Sie einige Details dazu angeben, könnten wir das Problem genauer diskutieren.

+0

Das ist eine gute Analyse der Grundursache. Immer einen Schritt zurück zuerst. –

4

Im abscence eines „default“ Mitglied, ich glaube, es um einen Wert haben repräsentiert die wörtliche wertvoll int 0

Egal was passiert, wird eine gegebene Enum mit wörtlichen Wert erstellt werden 0. Die meisten Gerade Fall ist hier als Mitglied einer Struktur. Eine C# -Struktur hat immer einen leeren Standardkonstruktor, der alle Felder auf ihren Standardwert initialisiert. Im Fall einer Enumeration ist das der Literalwert 0. Die Frage ist, wie man damit umgeht.

Für mich ist dies ein Problem des Stils: Wenn die enum nicht explizit auf einen Wert initialisiert wird, sollte es einen beliebigen gültigen Wert oder einen bestimmten Wert geben, der eine fehlende explizite Initialisierung anzeigt?

enum Color { Unknown, Red, Blue } 
enum Color2 { Red,Blue } 
struct Example<T> { 
    Color color; 
} 

static void SomeMethod() { 
    var v1 = new Example<Color>(); 
    var v2 = new Example<Color2>(); 
} 

Wenn v1 das Farbfeld überprüft wird, wird es explizit als nicht initialisiertes Feld gekennzeichnet. In v2 wird das Feld einfach "Rot" sein. Es gibt keine Möglichkeit für einen Programmierer, zwischen "Explizit gesetzt" auf "Rot" oder einem impliziten Standardwert zu "Rot" zu erkennen.

Ein anderer Fall, in dem dies ein Problem verursacht, ist eine Switch-Anweisung gegen einen Enum-Wert. Lässt leicht die Definition von Color2 ändern.

enum Color2 { Red = 1, Blue = 2 } 
static void SomeOtherMethod(p1 as Example<Color2>) { 
    switch (p1.color) { 
    case Color.Red: {} 
    case Color.Blue: {} 
    default: {throw new Exception("What happened?"); } 
    } 
} 

Der Switch verarbeitet jeden expliziten Wert in der Enumeration. Dieser Code wird jedoch für den Standardkonstruktor von Beispiel <Color2> fehlschlagen, und es gibt keine Möglichkeit, diesen Konstruktor zu unterdrücken.

Dies bringt eine slighly wichtige Regel auf: Haben Sie einen expliziten Enum-Wert für den wörtlichen Wert 0

+1

Ich bin mir nicht sicher, warum Sie eine explizite haben müssen Enum-Wert für 0. Lassen Sie es einfach aus, und initialisieren Sie explizit die anderen Werte - also zum Beispiel Rot = 1, Blau = 2. Dieselbe Wirkung zum größten Teil, aber Enum.GetValues ​​usw. enthalten nicht die "unbekannte "Wert. –

+0

Ich füge einen expliziten Wert hinzu, weil er Erwartungen entsprechend setzt. Es kann und wird 0 Wert-Instanzen dieser Aufzählung sein. Es ist eine unvermeidliche Konsequenz davon, sie als Werttyp-Mitglied zu verwenden Code klarer zu explizit dea l mit dem Unbekannten im Voraus. – JaredPar

+0

0 Werte werden als 0 angezeigt, ohne einen expliziten Wert, und es bedeutet, dass Sie sie nicht explizit entfernen müssen, wenn Sie die Liste der "echten" Werte betrachten. Ich denke, es hängt von der genauen Verwendung ab. –

7

ich einen meines Enum Literale immer auf Null gesetzt. Dieses Literal muss nicht immer "None" oder "NotSet" heißen. Es hängt davon ab, ob es ein Literal gibt, das sich sehr gut als Standard verhält.

Ich setze eins auf Null, weil enums (außer nullable enums) immer von der CLR im Speicher auf Null initialisiert werden. Und wenn Sie eines der Literale nicht definieren, enthält dieser Speicher ungültige Werte. Auch wenn Sie Enums als Flags verwenden. Der Standardwert kann nicht für bitweise Vergleiche verwendet werden. Das Ergebnis wird immer Null sein.

Wenn Sie FxCop aktivieren, prüft es, ob Sie ein Literal als Standard definiert haben. Scheint eine "gute Praxis" zu sein, wenn sie eine Regel dafür haben.

Verwandte Themen