Jak usunąć element dla wyliczenia OR?

181

Mam wyliczenie, takie jak:

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

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

Jak mogę usunąć kolor niebieski ze zmiennych kolorów?

Blankman
źródło
2
Mała uwaga: bitowe wyliczenie w języku C # powinno otrzymać nad nim atrybut [Flagi].
Nyerguds
@Nyerguds, czy możesz wyjaśnić, dlaczego powinien otrzymać atrybut?
etan
Daje lepszą obsługę IntelliSense podczas debugowania, ponieważ rozpoznaje nieznane wartości wyliczeniowe jako kombinacje istniejących wartości.
Nyerguds,
1
Zapewnia również bardziej znaczącą .ToString()wartość. np. RED, BLUE, YELLOWzamiast 22.
Sinjai

Odpowiedzi:

331

Musisz to &zrobić za pomocą ~(uzupełnienia) „NIEBIESKIEGO”.

Operator dopełniania zasadniczo odwraca lub „odwraca” wszystkie bity dla danego typu danych. Jako taki, jeśli użyjesz ANDoperatora ( &) z pewną wartością (nazwijmy tę wartość „X”) i dopełnieniem jednego lub więcej zestawów bitów (nazwijmy te bity Qi ich uzupełnienie ~Q), instrukcja X & ~Qusuwa wszelkie bity, które zostały ustawione w Qod Xi zwraca wynik.

Aby usunąć lub wyczyścić BLUEbity, użyj następującego oświadczenia:

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

Możesz również określić wiele bitów do wyczyszczenia, w następujący sposób:

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

lub na przemian ...

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

Podsumowując:

  • X | Q ustawia bity Q
  • X & ~Q usuwa bity Q
  • ~X odwraca / odwraca wszystkie bity X
SLaks
źródło
1
więc gdybym chciał usunąć więcej, po prostu zrobiłbym: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman
11
Lepiej jestcolors &= ~( Blah.BLUE | Blah.GREEN );
par
2
jak niezwykłe, po prostu zastanawiałem się, jak to zrobić jeszcze 5 dni temu :) To pytanie zaktualizowane w mojej skrzynce odbiorczej i voila!
Blankman
Świetna odpowiedź. Myślę jednak, że masz na myśli "& =" not "= &" w swoich przykładach kodu;)
Dave Jellison
48

Inne odpowiedzi są poprawne, ale aby konkretnie usunąć niebieski z powyższego, napiszesz:

colors &= ~Blah.BLUE;
par
źródło
9

And not to...............................

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;
Daniel A. White
źródło
7

Pomyślałem, że może to być przydatne dla innych osób, które potknęły się tutaj, jak ja.

Uważaj, jak radzisz sobie z wartościami wyliczania, które możesz ustawić na wartość == 0 (czasami pomocne może być posiadanie stanu nieznanego lub bezczynności dla wyliczenia). Powoduje to problemy przy korzystaniu z tych operacji manipulacji bitami.

Również gdy masz wartości wyliczane, które są kombinacjami innej potęgi 2 wartości, np

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

W takich przypadkach przydatna może być taka metoda rozszerzenia:

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

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

    return states & ~state;
}

A także ekwiwalentna metoda IsSet, która obsługuje połączone wartości (choć w nieco pospieszny sposób)

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
źródło
Wydaje mi się, że prostszym rozwiązaniem jest uniknięcie użycia 0 jako flagi. I zazwyczaj ustawić flagi stałe teksty jak ten . Nie rozumiem, w jaki sposób możesz czerpać korzyści z określania stanu o wartości 0. W końcu chodzi o to, że możesz zająć się nazwami przyjaznymi dla programisty ( Red, Blue, Green), a nie wartościami podstawowymi, tak?
Sinjai
Posiadanie wpisu nonelub unknownlub unseto wartości == 0 jest w wielu przypadkach dobrą rzeczą, ponieważ nie zawsze można założyć, że określona wartość jest ustawieniem domyślnym, np. Jeśli masz tylko czerwony, niebieski i zielony, czy masz czerwony jako wartość domyślna (np. wartość, która ma wyliczenie, gdy jest tworzony lub użytkownik go nie zmodyfikował?)
Sverrir Sigmundarson
Czy nie możesz po prostu 1, 2, 4, 8ustawić Unset = 1 i używać jako wartości? Jeśli potrzebujesz wartości domyślnej, po to są domyślne konstruktory, prawda? Chciałbym zachować wszystko tak wyraźnie, jak to możliwe, ze względu na czytelność, a poleganie na wyliczeniu domyślnym na default(int)( 0), gdy nie podano wartości, mimo że informacje są prawdopodobnie znane przez dowolnego programistę, jest i tak zbyt sprytne jak na mój gust. Edycja: Och, czekaj, czy ustawienie Unset = 0 uniemożliwi istnienie czegoś Unset | Blue?
Sinjai
Jesteś na dobrej drodze w swojej edycji Sinjai, utrzymywanie wartości nieustalonej == 0 faktycznie rozwiązuje kilka problemów. Jednym z nich jest to, o czym wspomniałeś, a drugim jest to, że jeśli rozbroisz wszystkie wartości wyliczenia, wtedy nie potrzebujesz specjalnego przypadku dla „Unset”, jeśli jest ustawiony na zero. (np. jeśli Red & ~Redskończysz na zero, będziesz musiał mieć kod, aby sprawdzić tę sprawę i wyraźnie przypisać Unsetwartość)
Sverrir Sigmundarson
Gotcha Czy często masz do czynienia z nieuzbrojonymi flagami?
Sinjai,
2

Co z XOR (^)?

Biorąc pod uwagę, że flaga FLAG, którą próbujesz usunąć, już tam jest, będzie działać .. jeśli nie, będziesz musiał użyć &.

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;
użytkownik4509414
źródło
1

Aby uprościć wyliczanie flagi i sprawić, że lepiej będzie czytać unikając wielokrotności, możemy użyć przesunięcia bitów. (Z dobrego artykułu Kończenie wielkiej debaty na temat flag Enum )

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

a także wyczyścić wszystkie bity

private static void ClearAllBits()
{
    colors = colors & ~colors;
}
Matt Allen
źródło
0

Możesz użyć tego:

colors &= ~Blah.RED; 
Majid Gharaei
źródło