Für mein Leben kann ich mich nicht erinnern, wie ich ein bisschen in einem Bitfeld gesetzt, gelöscht, umgeschaltet oder getestet habe. Entweder bin ich mir nicht sicher oder ich vermische sie, weil ich sie selten brauche. Ein "Bit-Spickzettel" wäre also schön zu haben.
Beispielsweise:
flags = flags | FlagsEnum.Bit4; // Set bit 4.
oder
if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?
Können Sie Beispiele für alle anderen gängigen Operationen geben, vorzugsweise in C # -Syntax unter Verwendung einer [Flags] -Aufzählung?
Antworten:
Ich habe noch etwas an diesen Erweiterungen gearbeitet - den Code finden Sie hier
Ich habe einige Erweiterungsmethoden geschrieben, die System.Enum erweitern, die ich häufig verwende ... Ich behaupte nicht, dass sie kugelsicher sind, aber sie haben geholfen ... Kommentare entfernt ...
Dann werden sie wie folgt verwendet
quelle
HasFlag
MethodeEnum
erfordert Boxen.In .NET 4 können Sie jetzt schreiben:
quelle
FlagsEnum
es ein hässlicher Name ist. :)[Flags]
Aufzählungen pluralisierte Namen haben sollten, sodass der NameFlagsEnum
noch schwerwiegendere Probleme als Hässlichkeit aufweist.Die Redewendung besteht darin, den bitweisen oder gleichen Operator zum Setzen von Bits zu verwenden:
Um ein bisschen zu löschen, lautet die Redewendung bitweise und mit Negation:
Manchmal haben Sie einen Versatz, der Ihr Bit identifiziert, und dann besteht die Redewendung darin, diese in Kombination mit der Linksverschiebung zu verwenden:
quelle
@ Zeichnete
Beachten Sie, dass Enum.HasFlag, außer in den einfachsten Fällen, im Vergleich zum manuellen Schreiben des Codes eine erhebliche Leistungseinbuße mit sich bringt. Betrachten Sie den folgenden Code:
Über 10 Millionen Iterationen benötigt die HasFlags-Erweiterungsmethode satte 4793 ms, verglichen mit 27 ms für die standardmäßige bitweise Implementierung.
quelle
HasFlag
Methode beinhaltet Boxen / Unboxen, was diesen Unterschied erklärt. Aber die Kosten sind so gering (0,4 µs), dass ich jeden Tag den besser lesbaren (und weniger wahrscheinlich fehlerhaften) deklarativen API-Aufruf annehmen würde, wenn Sie sich nicht in einer engen Schleife befinden.Die in .NET integrierten Flag-Enum-Operationen sind leider recht begrenzt. Meistens müssen Benutzer die bitweise Operationslogik herausfinden.
In .NET 4 wurde die Methode
HasFlag
hinzugefügt,Enum
die den Benutzercode vereinfacht, aber leider gibt es viele Probleme damit.HasFlag
ist nicht typsicher, da es jede Art von Aufzählungswertargument akzeptiert, nicht nur den angegebenen Aufzählungstyp.HasFlag
ist nicht eindeutig, ob geprüft wird, ob der Wert alle oder einige der vom Argument enum value bereitgestellten Flags enthält. Es ist übrigens alles.HasFlag
ist ziemlich langsam, da es Boxen erfordert, was Zuordnungen und damit mehr Speicherbereinigungen verursacht.Zum Teil aufgrund der eingeschränkten Unterstützung von .NET für Flag-Enums habe ich die OSS-Bibliothek Enums.NET geschrieben die jedes dieser Probleme behebt und den Umgang mit Flaggenaufzählungen erheblich erleichtert.
Im Folgenden sind einige der Vorgänge aufgeführt, die zusammen mit den entsprechenden Implementierungen nur mit dem .NET-Framework bereitgestellt werden.
Flaggen kombinieren
.NETZ
flags | otherFlags
Enums.NET
flags.CombineFlags(otherFlags)
Fahnen entfernen
.NETZ
flags & ~otherFlags
Enums.NET
flags.RemoveFlags(otherFlags)
Gemeinsame Flaggen
.NETZ
flags & otherFlags
Enums.NET
flags.CommonFlags(otherFlags)
Flaggen umschalten
.NETZ
flags ^ otherFlags
Enums.NET
flags.ToggleFlags(otherFlags)
Hat alle Flaggen
.NET
(flags & otherFlags) == otherFlags
oderflags.HasFlag(otherFlags)
Enums.NET
flags.HasAllFlags(otherFlags)
Hat irgendwelche Flaggen
.NETZ
(flags & otherFlags) != 0
Enums.NET
flags.HasAnyFlags(otherFlags)
Fahnen holen
.NETZ
Enums.NET
flags.GetFlags()
Ich versuche, diese Verbesserungen in .NET Core und möglicherweise in das vollständige .NET Framework zu integrieren. Sie können meinen Vorschlag hier überprüfen .
quelle
C ++ - Syntax unter der Annahme, dass Bit 0 LSB ist, unter der Annahme, dass Flags lange ohne Vorzeichen sind:
Überprüfen Sie, ob Set:
Überprüfen Sie, ob nicht festgelegt:
Einstellen:
Klar:
Umschalten:
quelle
Verwenden Sie Folgendes, um die beste Leistung und keinen Müll zu erzielen:
quelle
Um ein Bit zu testen, gehen Sie wie folgt vor: (Angenommen, Flags sind eine 32-Bit-Zahl)
Testbit:
(Wenn Bit 4 gesetzt ist, ist es wahr.) Zurückschalten (1 - 0 oder 0 - 1): Setzen Sie Bit 4 auf Null zurück:quelle
~0x08
anstatt0xFFFFFFF7
... (die eigentliche Maske für 0x8)Dies wurde durch die Verwendung von Sets als Indexer in Delphi inspiriert, als:
quelle
C ++ - Operationen sind: & | ^ ~ (für und oder oder xoder und nicht bitweise Operationen). Interessant sind auch >> und <<, bei denen es sich um Bitshift-Operationen handelt.
Um zu testen, ob ein Bit in einem Flag gesetzt ist, verwenden Sie: if (flags & 8) // testet Bit 4 wurde gesetzt
quelle