Wie entferne ich einen Artikel für eine OR-Aufzählung?

180

Ich habe eine Aufzählung wie:

public enum Blah
{
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16
}

Blah colors = Blah.RED | Blah.BLUE | Blah.YELLOW;

Wie kann ich die Farbe Blau aus den variablen Farben entfernen?

Blankman
quelle
2
Kleiner Hinweis: Eine bitweise Aufzählung in C # sollte das Attribut [Flags] darüber haben.
Nyerguds
@ Nyerguds, kannst du erklären, warum es das Attribut bekommen soll?
Ethan
Es bietet eine bessere IntelliSense-Unterstützung beim Debuggen, da unbekannte Aufzählungswerte als Kombinationen vorhandener Werte erkannt werden.
Nyerguds
1
Es bietet auch einen aussagekräftigeren .ToString()Wert. zB RED, BLUE, YELLOWeher als 22.
Sinjai

Antworten:

328

Sie müssen &es mit der ~(Ergänzung) von 'BLAU'.

Der Komplementoperator kehrt im Wesentlichen alle Bits für den gegebenen Datentyp um oder "dreht" sie um. Wenn Sie also den ANDOperator ( &) mit einem Wert (nennen wir diesen Wert 'X') und dem Komplement eines oder mehrerer gesetzter Bits (nennen wir diese Bits Qund deren Komplement ~Q) verwenden, X & ~Qlöscht die Anweisung alle Bits, die gesetzt wurden Qfrom Xund gibt das Ergebnis zurück.

Um die BLUEBits zu entfernen oder zu löschen , verwenden Sie die folgende Anweisung:

colorsWithoutBlue = colors & ~Blah.BLUE
colors &= ~Blah.BLUE // This one removes the bit from 'colors' itself

Sie können auch mehrere zu löschende Bits wie folgt angeben:

colorsWithoutBlueOrRed = colors & ~(Blah.BLUE | Blah.RED)
colors &= ~(Blah.BLUE | Blah.RED) // This one removes both bits from 'colors' itself

oder alternativ ...

colorsWithoutBlueOrRed = colors & ~Blah.BLUE & ~Blah.RED
colors &= ~Blah.BLUE & ~Blah.RED // This one removes both bits from 'colors' itself

Um es zusammenzufassen:

  • X | Q setzt Bit (s) Q
  • X & ~Q löscht Bit (s) Q
  • ~X kippt / invertiert alle Bits in X
SLaks
quelle
1
Wenn ich also mehr entfernen wollte, würde ich einfach Folgendes tun: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman
11
Besser istcolors &= ~( Blah.BLUE | Blah.GREEN );
Par
2
Wie ungewöhnlich, ich habe gerade darüber nachgedacht, wie ich das noch einmal machen soll. Vor ungefähr 5 Tagen :) Diese Frage wurde in meinem Posteingang und in meinem Voila aktualisiert!
Blankman
Gute Antwort. Ich denke du meinst jedoch "& =" nicht "= &" in deinen Codebeispielen;)
Dave Jellison
47

Die anderen Antworten sind richtig, aber um Blau von oben zu entfernen, würden Sie schreiben:

colors &= ~Blah.BLUE;
Par
quelle
9

And not es...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;
Daniel A. White
quelle
7

Dachte, dies könnte für andere Leute nützlich sein, die hier wie ich gestolpert sind.

Seien Sie vorsichtig, wie Sie mit Aufzählungswerten umgehen, für die Sie möglicherweise den Wert == 0 festgelegt haben (manchmal kann es hilfreich sein, für eine Aufzählung den Status "Unbekannt" oder "Leerlauf" zu verwenden). Es verursacht Probleme, wenn Sie sich auf diese Bitmanipulationsoperationen verlassen.

Auch wenn Sie Aufzählungswerte haben, die Kombinationen aus anderen Potenzen von 2 Werten sind, z

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

In diesen Fällen kann eine solche Erweiterungsmethode nützlich sein:

public static Colour UnSet(this Colour states, Colour state)
{
    if ((int)states == 0)
        return states;

    if (states == state)
        return Colour.None;

    return states & ~state;
}

Und auch die gleichwertige IsSet-Methode, die die kombinierten Werte behandelt (wenn auch etwas hackig)

public static bool IsSet(this Colour states, Colour state)
{
    // By default if not OR'd
    if (states == state)
        return true;

    // Combined: One or more bits need to be set
    if( state == Colour.Orange )
        return 0 != (int)(states & state);

    // Non-combined: all bits need to be set
    return (states & state) == state;
}
Sverrir Sigmundarson
quelle
Es scheint mir, dass die einfachere Lösung darin besteht, die Verwendung von 0 als Flag zu vermeiden. Ich typischerweise Flagge Aufzählungen wie aufgebaut dies . Ich verstehe nicht, wie Sie von der Angabe eines Status mit dem Wert 0 profitieren. Schließlich geht es darum, dass Sie sich eher mit den programmiererfreundlichen Namen ( Red, Blue, Green) als mit den zugrunde liegenden Werten befassen können , ja?
Sinjai
Ein noneoder unknownoder unsetEintrag mit dem Wert == 0 ist in vielen Fällen eine gute Sache, da Sie nicht immer davon ausgehen können, dass ein bestimmter Wert die Standardeinstellung ist. Wenn Sie beispielsweise nur Rot, Blau und Grün haben, haben Sie Rot als der Standardwert (z. B. der Wert, den die Aufzählung hat, wenn sie erstellt wird oder der Benutzer sie nicht geändert hat?)
Sverrir Sigmundarson
Können Sie nicht einfach Unset = 1 haben und 1, 2, 4, 8als Ihre Werte verwenden? Wenn Sie einen Standardwert benötigen, sind dies die Standardkonstruktoren, oder? Ich mag es, die Dinge aus Gründen der Lesbarkeit so explizit wie möglich zu halten, und mich auf eine Aufzählung zu verlassen, die standardmäßig auf default(int)( 0) gesetzt wird, wenn kein Wert angegeben wird, obwohl dies Informationen sind, die vermutlich jedem Entwickler bekannt sind, ist für meinen Geschmack sowieso zu hinterhältig. Edit: Oh warte, würde Unset = 0 verhindern, dass etwas ist Unset | Blue?
Sinjai
Sie sind in Ihrer Bearbeitung von Sinjai auf dem richtigen Weg. Wenn Sie den nicht festgelegten Wert == 0 beibehalten, werden einige Probleme behoben. Eine ist das, was Sie erwähnt haben, und eine andere ist, wenn Sie alle Enum-Werte deaktiviert haben, dann brauchen Sie keinen Sonderfall für "Unset", wenn es auf Null gesetzt ist. (zB wenn Sie Red & ~Reddann mit Null enden, müssten Sie Code haben, um diesen Fall zu überprüfen und den UnsetWert explizit zuzuweisen )
Sverrir Sigmundarson
Erwischt. Haben Sie es oft mit nicht gesetzten Flags zu tun?
Sinjai
2

Was ist mit xor (^)?

Vorausgesetzt, dass die FLAG, die Sie entfernen möchten, vorhanden ist, funktioniert sie. Wenn nicht, müssen Sie ein & verwenden.

public enum Colour
{
    None = 0,  // default value
    RED = 2,
    BLUE = 4,
    GREEN = 8,
    YELLOW = 16,
    Orange = 18  // Combined value of RED and YELLOW
}

colors = (colors ^ Colour.RED) & colors;
user4509414
quelle
1

Um die Flag-Aufzählung zu vereinfachen und das Lesen durch Vermeiden von Vielfachen zu verbessern, können wir die Bitverschiebung verwenden. (Aus einem guten Artikel zum Ende der großen Debatte über Enum Flags )

[FLAG]
Enum Blah
{
   RED = 1,
   BLUE = 1 << 1,
   GREEN = 1 << 2,
   YELLOW = 1 << 3
}

und auch alle Bits zu löschen

private static void ClearAllBits()
{
    colors = colors & ~colors;
}
Matt Allen
quelle
0

Sie können dies verwenden:

colors &= ~Blah.RED; 
Majid Gharaei
quelle