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?


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

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;

9

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

Blah.RED | Blah.YELLOW == 
   (Blah.RED | Blah.BLUE | Blah.YELLOW) & ~Blah.BLUE;

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;
}

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;

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;
}

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.