Kapitel 21 Aufzählungsbezeichner
Aufzählungsbezeichner sind hilfreich, wenn
ein Wert im Programm nur über einen spezifischen Satz Werte verfügen
kann. Ein Steuerelement, dass nur eine von vier Farben annehmen kann,
oder ein Netzwerkpaket, das nur zwei Protokolle unterstützt, das
sind beispielsweise Fälle, in denen ein Aufzählungsbezeichner
zu einer Codeoptimierung beitragen kann.
21.1 Eine Beispielaufzählung
 
Im folgenden Beispiel verwendet eine Linienklasse
eine Aufzählung zum Deklarieren der verschiedenen Linienstile:
using System;
public class Draw
{
public enum LineStyle
{
Solid,
Dotted,
DotDash,
}
public void DrawLine(int x1, int y1, int x2, int y2, LineStyle lineStyle)
{
switch (lineStyle)
{
case LineStyle.Solid:
// durchgehende Linie zeichnen
break;
case LineStyle.Dotted:
// gepunktete Linie zeichnen
break;
case LineStyle.DotDash:
// Linie aus Punkten und Strichen zeichnen
break;
default:
throw(new ArgumentException("Invalid line style"));
}
}
}
class Test
{
public static void Main()
{
Draw draw = new Draw();
draw.DrawLine(0, 0, 10, 10, Draw.LineStyle.Solid);
draw.DrawLine(5, 6, 23, 3, (Draw.LineStyle) 35);
}
}
Mit enum LineStyle werden die
Werte definiert, die für die Aufzählung angegeben werden können.
Anschließend wird genau diese Aufzählung in der Funktion zur
Angabe des zu zeichnenden Linientyps verwendet.
Obwohl mit Aufzählungsbezeichnern die versehentliche
Verwendung von Werten verhindert wird, die außerhalb des enum-Bereichs
liegen, bleiben die Werte für eine Aufzählung nicht auf die
Bezeichner in der enum-Deklaration beschränkt. Der
zweite Aufruf von DrawLine() ist zulässig, ein an
eine Funktion übergebener enum-Wert muss also weiterhin
validiert werden, um sicherzustellen, dass er sich im Bereich der gültigen
Werte befindet. Die Draw-Klasse erzeugt eine Argumentausnahme,
wenn das Argument ungültig ist.
21.2 Basistypen für Aufzählungsbezeichner
 
Jeder Aufzählungsbezeichner weist einen zugrunde
liegenden Typ auf, der angibt, wie viel Speicher diesem Bezeichner zugeordnet
ist. Die gültigen Basistypen für Aufzählungsbezeichner
sind byte, sbyte, short, ushort,
int, uint, long und ulong.
Ist der Basistyp nicht spezifiziert, lautet er standardmäßig
int. Der Basistyp wird festgelegt, indem er dem enum-Namen
nachgestellt wird:
enum SmallEnum : byte
{
A,
B,
C,
D
}
Das Angeben des Basistyps kann nützlich sein,
wenn die Größe eine Rolle spielt oder wenn die Anzahl der
Einträge die Anzahl möglicher Werte für int
übersteigen würde.
21.3 Initialisierung
 
Standardmäßig wird der Wert für das
erste enum-Mitglied auf 0 gesetzt und für jedes
nachfolgende Mitglied erhöht. Mit dem Mitgliedsnamen können
spezifische Werte festgelegt werden:
enum Values
{
A = 1,
B = 5,
C = 3,
D = 42
}
Es können auch berechnete Werte verwendet werden,
solange diese auf Werten beruhen, die bereits in der Aufzählung
definiert wurden:
enum Values
{
A = 1,
B = 2,
C = A + B,
D = A * C + 33
}
Wird eine Aufzählung ohne Nullwert deklariert,
kann dies zu Problemen führen, da es sich bei 0 um den Standardinitialisierungswert
für die Aufzählung handelt:
enum Values
{
A = 1,
B = 2,
C = A + B,
D = A * C + 33
}
class Test
{
public static void Member(Values value)
{
// Hier ein bisschen Verarbeitung
}
public static void Main()
{
Values value = 0;
Member(value);
}
}
Als Teil einer Aufzählung sollte stets ein
Mitglied mit dem Wert 0 definiert werden.
21.4 Bitflagaufzählungen
 
Aufzählungen können auch als Bitflags
verwendet werden, indem für jedes Bit ein anderer Bitwert angegeben
wird. Hier eine typische Definition:
[Flags]
enum BitValues
{
NoBits = 0,
Bit1 = 0x00000001,
Bit2 = 0x00000002,
Bit3 = 0x00000004,
Bit4 = 0x00000008,
Bit5 = 0x00000010,
AllBits = 0xFFFFFFFF
}
class Test
{
public static void Member(BitValues value)
{
// Hier ein bisschen Verarbeitung
}
public static void Main()
{
Member(BitValues.Bit1 | BitValues.Bit2);
}
}
Das [Flag]-Attribut vor der enum-Definition
unterstützt Designer und Browser dabei, Schnittstellen für
Flagaufzählungen zu kennzeichnen. In solchen Aufzählungen
ist es sinnvoll, dem Benutzer das Verketten verschiedener Bits über
ein OR zu ermöglichen, was bei Nichtflagaufzählungen unnütz
wäre.
Die Main()-Funktion verkettet über
OR zwei Bitwerte und übergibt den Wert an die Mitgliedsfunktion.
21.5 Konvertierungen
 
Aufzählungstypen können explizit in den
zugrunde liegenden Typ und zurück konvertiert werden.
enum Values
{
A = 1,
B = 5,
C = 3,
D = 42
}
class Test
{
public static void Main()
{
Values v = (Values) 2;
int ival = (int) v;
}
}
Die einzige Ausnahme hierbei ist, dass der literale
Wert 0 ohne cast in einen
enum-Typ konvertiert werden kann. Es ist also folgender
Code möglich:
public void DoSomething(BitValues bv)
{
if (bv == 0)
{
}
}
Die if-Anweisung müsste:
if (bv == (BitValues) 0)
lauten, wenn es diese Ausnahme nicht gäbe.
Im vorliegenden Beispiel ist dies nicht weiter schlimm, kann jedoch
lästig werden, wenn die Aufzählung tief in der Hierarchie
verschachtelt ist:
if (bv == (CornSoft.PlotLibrary.Drawing.LineStyle.BitValues)
0)
Eine Menge Eingabeaufwand.
|