Angenommen, ich habe Folgendes
int susan = 2; //0010
int bob = 4; //0100
int karen = 8; //1000
und ich übergebe 10 (8 + 2) als Parameter an eine Methode und möchte dies dekodieren, um Susan und Karen zu bedeuten
Ich weiß, dass 10 1010 ist
aber wie kann ich eine Logik machen, um zu sehen, ob ein bestimmtes Bit wie in eingecheckt ist
if (condition_for_karen) // How to quickly check whether effective karen bit is 1
Im Moment kann ich nur daran denken, zu überprüfen, ob die Nummer, die ich übergeben habe, ist
14 // 1110
12 // 1100
10 // 1010
8 // 1000
Wenn ich in meinem realen Szenario eine größere Anzahl von tatsächlichen Bits habe, erscheint dies unpraktisch. Was ist eine bessere Möglichkeit, mit einer Maske zu überprüfen, ob ich die Bedingung für nur Karen erfülle oder nicht?
Ich kann mir vorstellen, nach links und zurück zu wechseln, dann nach rechts und dann zurück, um andere Teile als die zu löschen, an denen ich interessiert bin, aber dies scheint auch zu komplex zu sein.
Antworten:
Der traditionelle Weg, dies zu tun, besteht darin, das
Flags
Attribut für Folgendes zu verwendenenum
:Dann würden Sie wie folgt nach einem bestimmten Namen suchen:
Logische bitweise Kombinationen können schwer zu merken sein, daher mache ich mir das Leben mit einer
FlagsHelper
Klasse * leichter :Dies würde es mir ermöglichen, den obigen Code wie folgt umzuschreiben:
Hinweis: Ich könnte
Karen
dem Set auch Folgendes hinzufügen :Und ich könnte
Susan
auf ähnliche Weise entfernen :* Wie Porges hervorhob,
IsSet
gibt es in .NET 4.0 bereits ein Äquivalent der oben genannten Methode :Enum.HasFlag
. Die MethodenSet
undUnset
scheinen jedoch keine Entsprechungen zu haben. Daher würde ich immer noch sagen, dass diese Klasse einen gewissen Wert hat.Hinweis: Die Verwendung von Aufzählungen ist nur die herkömmliche Methode, um dieses Problem zu lösen. Sie können den gesamten obigen Code vollständig übersetzen, um stattdessen Ints zu verwenden, und es wird genauso gut funktionieren.
quelle
(names & Names.Susan) == Names.Susan
, was keine erfordertNone
.None
Wert für alle meine Aufzählungen zu definieren, da ich finde, dass dies in vielen Szenarien praktisch ist.var susanIsIncluded = names.HasFlag(Names.Susan);
Set
Methode. Daher würde ich sagen, dass die Hilfsmethoden zumindest nicht völlig wertlos sind.)names.HasFlag(Names.Susan)
wie ist,(names & Names.Susan) == Names.Susan
was nicht immer wie ist(names & Names.Susan) != Names.None
. Zum Beispiel, wenn Sie überprüfen, obnames.HasFlag(Names.none)
odernames.HasFlag(Names.Susan|Names.Karen)
Das bitweise 'und' maskiert alles außer dem Bit, das Karen "darstellt". Solange jede Person durch eine einzelne Bitposition dargestellt wird, können Sie mehrere Personen mit einem einfachen:
quelle
Ich habe hier ein Beispiel beigefügt, das zeigt, wie Sie die Maske in einer Datenbankspalte als int speichern und wie Sie die Maske später wieder herstellen können:
quelle
Um Bitmasken zu kombinieren, möchten Sie bitweise oder verwenden . In dem trivialen Fall, in dem jeder Wert, den Sie kombinieren, genau 1 Bit enthält (wie in Ihrem Beispiel), entspricht dies dem Hinzufügen. Wenn Sie jedoch überlappende Bits haben oder diese bearbeiten, wird der Fall ordnungsgemäß behandelt.
So entschlüsseln Sie die Bitmasken Sie und Ihren Wert mit einer Maske wie folgt :
quelle
Einfacher Weg:
Verwenden Sie zum Setzen der Flags den logischen Operator "oder"
|
:Und um zu überprüfen, ob eine Flagge enthalten ist, verwenden Sie
HasFlag
:quelle
HasFlag()
und[Flags]
wurde in anderen Antworten nicht angegeben.Ein weiterer wirklich guter Grund, eine Bitmaske gegen einzelne Bools zu verwenden, ist, dass wir als Webentwickler bei der Integration einer Website in eine andere häufig Parameter oder Flags im Querystring senden müssen. Solange alle Ihre Flags binär sind, ist es viel einfacher, einen einzelnen Wert als Bitmaske zu verwenden, als mehrere Werte als Bools zu senden. Ich weiß, dass es andere Möglichkeiten gibt, Daten zu senden (GET, POST usw.), aber ein einfacher Parameter auf dem Querystring reicht meistens für nicht sensible Elemente aus. Versuchen Sie, 128 Bool-Werte auf einem Querystring zu senden, um mit einer externen Site zu kommunizieren. Dies bietet auch die zusätzliche Möglichkeit, das Limit für URL-Abfrageringe in Browsern nicht zu überschreiten
quelle