Come rimuovere un elemento per un enum OR?


181

Ho un enum come:

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

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

Come potrei rimuovere il colore blu dai colori variabili?


2
Piccola nota: un'enumerazione bit a bit in C # dovrebbe ottenere l'attributo [Flags] sopra di esso.
Nyerguds,

@Nyerguds, potresti spiegare perché dovrebbe ottenere l'attributo?
etano,

Offre un supporto IntelliSense migliore durante il debug, poiché riconosce i valori enum sconosciuti come combinazioni di valori esistenti.
Nyerguds,

1
Fornisce inoltre un .ToString()valore più significativo . ad es. RED, BLUE, YELLOWanziché 22.
Sinjai,

Risposte:


331

È necessario &con il ~(complemento) di 'BLU'.

L'operatore del complemento essenzialmente inverte o "capovolge" tutti i bit per il tipo di dati specificato. Pertanto, se si utilizza l' ANDoperatore ( &) con un certo valore (chiamiamo quel valore 'X') e il complemento di uno o più bit impostati (chiamiamo quei bit Qe il loro complemento ~Q), l'istruzione X & ~Qcancella tutti i bit impostati in Qda Xe restituisce il risultato.

Quindi, per rimuovere o cancellare i BLUEbit, utilizzare la seguente istruzione:

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

È inoltre possibile specificare più bit da cancellare, come segue:

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

o alternativamente ...

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

Quindi per riassumere:

  • X | Q imposta bit Q
  • X & ~Q cancella bit Q
  • ~X inverte / inverte tutti i bit in X

1
quindi se volessi rimuovere altro farei semplicemente: & = ~ Blah.BLUE & ~ Blah.Green?
Blankman,

11
Meglio ècolors &= ~( Blah.BLUE | Blah.GREEN );
par

2
che insolito, stavo solo pensando a come farlo ancora circa 5 giorni fa :) Questa domanda è stata aggiornata nella mia casella di posta e voilà!
Blankman,

Bella risposta. Penso che tu intenda "& =" non "= &" nei tuoi esempi di codice;)
Dave Jellison,

48

Le altre risposte sono corrette, ma per rimuovere specificamente il blu da quanto sopra dovresti scrivere:

colors &= ~Blah.BLUE;

9

And not esso ...............................

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

7

Pensavo che ciò potesse essere utile per altre persone che sono inciampate qui come me.

Fai attenzione a come gestisci i valori enum che potresti impostare per avere un valore == 0 (a volte può essere utile avere uno stato Inattivo o Inattivo per un enum). Causa problemi quando si fa affidamento su queste operazioni di manipolazione dei bit.

Anche quando hai valori enum che sono combinazioni di altra potenza di 2 valori, ad es

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

In questi casi un metodo di estensione come questo potrebbe tornare utile:

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

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

    return states & ~state;
}

E anche l'equivalente metodo IsSet che gestisce i valori combinati (anche se in modo un po 'confuso)

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

Mi sembra che la soluzione più semplice sia evitare di usare 0 come flag. In genere ho impostato enumerazioni bandiera come questo . Non vedo come trarrai vantaggio dalla specifica di uno stato con un valore di 0. Dopotutto, il punto è che puoi occuparti dei nomi facili da programmare ( Red, Blue, Green) piuttosto che dei valori sottostanti, sì?
Sinjai,

Avere una noneo unknowno una unsetvoce con valore == 0 è in molti casi una buona cosa in quanto non si può sempre presumere che un determinato valore sia l'impostazione predefinita, ad esempio se si dispone solo di Rosso, Blu e Verde, si avrà il rosso come il valore predefinito (ad es. il valore che l'enum ha quando viene creato o l'utente non l'ha modificato?)
Sverrir Sigmundarson,

Non puoi semplicemente avere Unset = 1 e usarlo 1, 2, 4, 8come valori? Se hai bisogno di un valore predefinito, ecco a cosa servono i costruttori predefiniti, giusto? Mi piace mantenere le cose il più esplicite possibile per motivi di leggibilità e fare affidamento su un enum su default a default(int)( 0) quando non viene dato un valore, nonostante siano presumibilmente informazioni conosciute da qualsiasi sviluppatore, è comunque troppo subdolo per i miei gusti. Modifica: Oh aspetta, rendere Unset = 0 impedirebbe che qualcosa si presenti Unset | Blue?
Sinjai,

Sei sulla strada giusta nella tua modifica Sinjai, mantenendo il valore non impostato == 0 risolve effettivamente alcuni problemi. Uno è quello che hai menzionato e un altro è se disinserisci tutti i valori enum allora non hai bisogno di un caso speciale per "Unset" se è impostato su zero. (es. se Red & ~Redpoi ti Unset
ritrovi

Gotcha. Ti capita spesso di avere a che fare con flag non impostati?
Sinjai

2

Che dire di xor (^)?

Dato che il FLAG che stai cercando di rimuovere è lì, funzionerà .. in caso contrario, dovrai usare un &.

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

Per semplificare l'enumerazione del flag e renderlo migliore da leggere evitando i multipli, possiamo usare lo spostamento dei bit. (Da un buon articolo che termina il grande dibattito sulle bandiere Enum )

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

e anche per cancellare tutti i bit

private static void ClearAllBits()
{
    colors = colors & ~colors;
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.