Dann hätte man so etwas:
Auch hier wird die Problematik schnell offensichtlich - Schreibfehler. Zudem kommt hinzu, dass der eine Entwickler in Unicode verliebt ist, der andere der Auffassung ist, dass dies immer problematisch ist und daher Umlaute ausschreibt.
Hier könnte man jetzt Enumerationen zum Einsatz bringen. Im Folgenden möchte ich die Möglichkeiten näher darstellen aber auch die Fehlerproblematik aufzeigen, die sich durch den Einsatz von Enumerationen ergeben kann.
Enumerationen sollten meines Erachtens immer eingesetzt werden, sobald es sich anbietet. Man kommt bisweilen aber um verschiedene Diskussionen nicht herum. Steigt man in ein gewachsenes Projekt ein, so kann man nicht daher kommen und alles einfach umändern. Man kann aber Brücken zum Erfolg und damit zu besserer Softwarequalität bauen.
Nehme ich mal das oben genannte Beispiel, wo im Methodenaufruf eine Zeichenkette übergeben wird. Hier ist die Argumentation ganz klar die Fehleranfälligkeit durch Schreibfehler. Das gilt es zu verhindern - erst Recht, wenn derartige Aufrufe mehrfach an verschiedenen Stellen im Projekt vorkommen. Andererseits sollte man nicht wie die Axt im Walde vorgehen, denn bei gewachsenen Anwendungen (auch wenn es Brownfieldprojekte sind) muss man bedenken, dass die Methodenlogik dennoch gewissermaßen getestet ist. Ziel sollte daher im ersten Schritt sein, nur die Methodendefinition anzupassen.
Als erstes erstelle ich hierzu eine Enumeration.
Im nächsten Schritt erstelle ich eine weitere Überladung der Methode
MachWas.
Nun wird deutlich, dass dies nicht wirklich funktionieren kann, hat doch das Eingangs gezeigte Beispiel gezeigt, dass im Fall von
EnumMachWas.SPAETER der Wert "später" erwartet wird. Der Aufruf der
ToString()-Methode ergibt aber "SPAETER". Der schnellste Weg wäre hier über eine
switch-
case-Anweisung zu gehen:
Aus meiner Sicht ist auch hier wieder problematisch, dass dieses Vorgehen sich an mehreren Stellen im Code wiederholen kann und das Problem des potentiellen Schreibfehlers fortbesteht.
Es wäre doch schön, wenn ich der Enumeration einfach per Definition einen bestimmten Wert zuweisen könnte, so nach dem Muster:
Spätestens beim kompilieren erfahren wir, dass dies so nicht geht. Man ist geneigt, per Definition die Enumeration vom Type
String abzuleiten. Aber auch das wird beim kompilieren mit einer Fehlermeldung quittiert:
"Type byte, sbyte, short, ushort, int, uint, long, or ulong expected" Doch eine Lösung muss es doch geben - oder?
Wer sich schon einmal auf die Suche nach einer passenden Lösung gemacht hat, bekommt über die Suchmaschine seiner Wahl als erstes die Fragestellung zu lesen: "
Wie kann ich die ToString()-Methode einer Enumeration überschreiben?". Leider lautet die Antwort hierzu: gar nicht - es geht einfach nicht.
Wie sieht die Sache aber eigentlich mit
Attributen aus - es sollte doch möglich sein, einem jeden
Field der Enumeration ein eigenes
Attribute zu verpassen. Wenn dies möglich ist, könnte man per Attributdefinition einen weiteren Wert z.B. vom Type
String zuweisen.
Bei der Definition einer eigenen Attributeklasse legt man in der Regel fest, wo dieses zulässig sein soll. Dazu wird der Attributeklasse das
Attribute AttributeUsage zugewiesen. Über
AttributeTargets wird dann deutlich, dass es möglich sein muss, Enumerationen mit Attributen zu versehen, da
Enum als auch
Field als
AttributeTargets angegeben werden kann. Da eine Enumeration erfahrungsgemäß immer aus mehr als einem Wert besteht, muss auch
AllowMultiple auf
true gesetzt werden.
Eine einfache Attributeklasse schaut demnach wie folgt aus:
Jetzt müssen den einzelnen Fields der Enumeration die Attribute zugewiesen werden.
Damit hat sich die Definition der Enumeration
EnumMachWas entsprechend geändert.
Doch wie erhalte ich jetzt die Attributewerte? Hier hilft eine
Extension Methods weiter.
Das Beispiel ist an dieser Stelle bewusst etwas einfach gehalten. Hier ist alles auf nur einem Attribute eines bestimmten Attributetypes und auf die Eigenschaft Text festgelegt. Es empfielt sich an dieser Stelle, eine generische Methode zu definieren und hinsichtlich der Eigenschaften wieder auf Enumerationen zurückzugreifen. Im ersten Schritt geht es jetzt erst einmal nur um das generelle Prinzip, was mit dem o.g. Beispiel deutlich wird.
Wenn man jetzt auf den Attributewert der Enumeration
EnumMachWas zugreifen möchte, braucht man nur noch die Methode
GetAttribute() aufzurufen.
Jetzt werden die Vorteile des Einsatzes von Enumerationen wieder deutlich: man kann an einer zentralen Stelle diese definieren und ohne größeren Umbau in gewachsene Projekte einführen. Gerade im Rahmen der komponentenorientierten Entwicklung ist es unerlässlich, Codeduplizierungen zu vermeiden - Enumerationen sind dabei eine sehr gute Unterstützung. Weiter unterstützen sie bei der Vermeidung von Schreibfehlern und den damit verbundenen Schwierigkeiten.
Bei aller Euphorie können aber immer noch Probleme in der Verwendung von Enumerationen auftreten. Was passiert bei folgender Definition:
Möchte ich jetzt nachstehenden Aufruf umsetzen,
so erhalte ich folgende fehlerhafte Ausgabe:
Doch warum ist das so? Der Fehler liegt wohl in der internen Verarbeitung der Enumeration. Es bleibt zu hoffen, dass dies in einer der nächsten Frameworkversionen behoben sein wird.
Im Fazit heißt es, sobald Werte den Fielddefinitionen zugewiesen werden, sollten entweder alle Felder einen Wert zugewiesen bekommen oder nach dem FieldValue sortiert werden. Alternativ könnte man aber auch hier wieder auf Attribute zurückgreifen.
Im Ergebnis kann man aber sagen, dass Enumerationen die Arbeit deutlich unterstützen können - nicht zu Letzt, da sie maßgeblich zur Lesbarkeit des Codes (auch nach Jahren) beitragen. Durch die Verwendung von Attributen kann man Enumerationen recht vielseitig einsetzen, ohne dabei auf dem der Enumeration typischen Wertebereich beschränkt zu sein.