2010-09-16 15 views
10

Wenn Aufzählungen mit Bit-Felder mit:Gibt es eine andere Möglichkeit, Enum-Bitfelder zu testen?

enum ReallyBigEnum { FirstChoice = 0x01, AnotherOption = 0x02 } 
    ReallyBigEnum flag = ReallyBigEnum.FirstChoice | ReallyBigEnum.AnotherOption; 

der Code verwendet, um die Bits zu testen, ist: das Bit getestet zu wiederholen

if((flag & ReallyBigEnum.AnotherOption) == ReallyBigEnum.AnotherOption) { ... } 

, die wegen der Notwendigkeit, die ausführliche und fehleranfällig zu sein scheint.

Es wäre schön, wenn es eine Möglichkeit zu sagen, ist:

if(flag.IsSet(ReallyBigEnum.AnotherOption)) { ... } 

aber Aufzählungen unterstützen keine Instanzmethoden. Also habe ich versucht, eine Template-Funktion:

class Enums 
    { 
     public static bool IsSet<T>(T flag, T bit) { return (flag & bit) == bit; } 
    } 

aber die Code-Bits zu testen, sieht dann wie folgt aus:

if(Enums.IsSet<ReallyBigEnum>(flag, ReallyBigEnum.AnotherOption)) { ... } 

, die eine Menge zu schreiben. Dann habe ich versucht, es zu verkürzen:

class Enums 
    { 
     public static bool IsSet(int flag, int bit) { return (flag & bit) == bit; } 
    } 

aber dann müssen Sie jeden Wert seinen Basistyp wie diese Stimmen:

if(Enums.IsSet((int)flag, (int)ReallyBigEnum.AnotherOption)) { ... } 

die auch ein Schmerz-Code ist und verlieren den Vorteil der Typprüfung .

Die gleiche Funktion könnte geschrieben werden, um 'Objekt' Parameter zu verwenden, aber dann der Objekttyp und zugrunde liegenden Basistyp müsste getestet werden.

Also, ich bin mit dem Standard, redundante Weg an der Spitze stecken.

Hat jemand andere Ideen auf eine saubere, einfache Art, Enum Bitfelder zu testen?

Viel Dank.

Antwort

6

Bis zu .Net 3.5 ist dies Ihre einzige Option. In .Net 4.0 gibt es eine HasFlag Methode auf der Enumeration.

+0

Die hasFlag() -Methode ist die perfekte Lösung, natürlich. Vielen Dank! Leider verwendet unsere Entwicklungsumgebung immer noch .NET 2.0. –

2
if((flag & ReallyBigEnum.AnotherOption) != 0) { ... } 

AKTUALISIERT:

Die oben arbeiten natürlich nur, wenn Sie ein einzelnes Bit zu testen sind. Wenn Sie mehrere Bits testen möchten, ist etwas anderes erforderlich, je nachdem, ob Sie nach alle Bits oder irgendein Bit suchen.

Testing, dass jeder eines Satzes von Bits gesetzt

Für diesen Fall verwenden nur eine Variante der Einzel-Bit-Version.

if((flag & (ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption)) != 0) { ... } 

Tests, die alle einen Satz von Bits

Für diesen Fall eingestellt wird Klarheit und Zuverlässigkeit achive, schlage ich vor, die Schaffung eine Konstante, die alle Bits enthält.

Einige der Redundanz ist immer noch da, aber es ist nicht fragil oder verwirrend, und es ist einfach zu pflegen.

Wenn die Bitkombination breit angewendet wird, können Sie sie zur Enumeration hinzufügen.

[Flags] 
enum ReallyBigEnum 
{ 
    FirstOption = 1, 
    AnotherOption = 2, 
    WickedAwesomeOptions = FirstOption | AnotherOption, 
} 
.... 
if (flag & ReallyBigEnum.WickedAwesomeOptions == ReallyBigEnum.WickedAwesomeOptions) { ... } 
+0

Dies entfernt die Redundanz, funktioniert aber nur, wenn alle Flags einzelne Bits sind. Zusammengesetzte Flags mit mehreren Bits können falsche positive Ergebnisse zurückgeben. –

+0

@Chris C. - Sicher funktioniert es nur mit Single-Bit-Flags. Genau darum geht es in der Frage. Kein Teil der Frage fragt nach mehreren Bits. –

+0

@Chris C. - Ich habe die Antwort geändert, um diese neue Frage zu beantworten. –

2
/// <summary> 
/// Taken from https://stackoverflow.com/questions/9033/hidden-features-of-c/407325#407325 
/// instead of doing (enum & value) == value you can now use enum.Has(value) 
/// </summary> 
/// <typeparam name="T">Type of enum</typeparam> 
/// <param name="type">The enum value you want to test</param> 
/// <param name="value">Flag Enum Value you're looking for</param> 
/// <returns>True if the type has value bit set</returns> 
public static bool Has<T>(this System.Enum type, T value) 
{ 
    return (((int)(object)type & (int)(object)value) == (int)(object)value); 
} 

Hier eine Erweiterungsmethode I vom

Verwendung above link nahm:

MyFlagEnum e = MyFlagEnum.First | MyFlagEnum.Second; 
if(e.Has(MyFlagEnum.First)) 
{ 
    // Do stuff 
} 
+0

Oh, aber Sie verwenden .NET 2, also keine Erweiterungsmethoden ... – PostMan

+0

Sehr gute Lösung. Die Dokumentation besagt, dass Erweiterungsmethoden für C# genauso effizient sind wie die ursprünglichen Klassenmethoden. Erweiterungsmethoden wurden in .NET v3.0 eingeführt. Dieser Code nimmt eine Annahme über die Größe der Enum vor, die auch auf vorzeichenlosen und langen ganzen Zahlen basieren kann. –

+1

Wenn die Umwandlung geändert wurde in: (Long) (Objekt) Wert würde es für alle Integer-Typen funktionieren? –

Verwandte Themen