2012-01-21 9 views
32

Voglio solo sapere se è impostato esattamente un flag enum, non quali. Il mio attuale pensiero è quello di verificare se è un potere di 2. C'è un modo migliore integrato nei tipi di enumerazione?Come posso verificare se è stato impostato più di un flag enum?

[Flags] 
enum Foo 
{ 
Flag1 = 0x01, 
Flag2 = 0x02, 
Flag3 = 0x04, 
Flag4 = 0x08, 
Flag5 = 0x10, 
Flag6 = 0x20, 
Flag7 = 0x40, 
Flag8 = 0x80 
} 

private bool ExactlynOneFlagSet(Foo myFoo) 
{ 
    var x = (byte) myFoo; 
    return (x != 0) && ((x & (x - 1)) == 0); //Check if a power of 2 
} 

if(!ExactlynOneFlagSet(Foo myFoo)) 
{ 
    //Do something 
} 
+0

Questo sembra piuttosto semplice, sì. Perché non farlo in quel modo? – Groo

+2

Si prega di non aggiungere il prefisso ai titoli con "C#:" e così via. Ecco a cosa servono i tag. –

+0

Perché ho la sensazione che questa sia una domanda "guarda la mia soluzione" mascherata da una domanda ... –

risposta

10
private bool ExatlyOneFlagSet(Foo myFoo) 
{ 
    return !myFoo.ToString().Contains(','); 
} 
+1

@MarkHall in.NET se è impostato più di un flag, la rappresentazione di stringa dell'enumerazione è un elenco delimitato da virgole. –

+1

@MarkHall L'attributo Flags consente di mostrare i singoli valori dei valori separati da virgole. Puoi andare avanti e provarlo. – itsme86

+0

I sta corretti –

7

Se l'enum non definisce combinazioni espliciti di bandiere, si può solo controllare se il valore è definito nel enum:

private bool ExactlynOneFlagSet(Foo myFoo) 
{ 
    return Enum.IsDefined(typeof(Foo), myFoo); 
} 
+0

Perché il downvote? –

+0

+1: Funziona, anche se l'enum definisce esplicitamente le combinazioni ('enum Foo {Nessuno = 0, A = 1, B = 2, C = 4, AB = A | B, BC = B | C, Tutto = A | B | C,} '). Specificando una delle combinazioni predefinite ('Enum.IsDefined (typeof (Foo), Foo.A | Foo.B)') darà 'true': è in effetti un valore definito. –

+0

@NicholasCarey, sì, restituirà true per AB, ma AB ha più di un bit impostato ... L'OP vuole sapere se c'è più di un bit impostato, non se il valore è definito. –

52

E 'un operazione Bit!

if ((myFoo & (myFoo -1)) != 0) //has more than 1 flag 

la dichiarazione controlla se il valore di myFoo non è potenza di due. Oppure, vice versa, la dichiarazione (myFoo & (myFoo -1)) == 0 controlla la potenza di due. L'idea è che solo i valori di un singolo flag saranno due. L'impostazione di più di un flag comporterà l'assenza del valore di due valori di .

Ulteriori informazioni possono essere trovate in questa risposta a una domanda simile: https://stackoverflow.com/a/1662162/2404788.

Per ulteriori informazioni sulle operazioni bit vanno a http://en.wikipedia.org/wiki/Bitwise_operation

+3

+1, soluzione molto elegante! –

+0

@Guido Ottima soluzione. Puoi aggiungere qualche spiegazione per favore? – Shimmy

+0

Grazie @Shimmy. Ho aggiunto una spiegazione di base. Spero che sia utile –

0

Come Jacob ha spiegato in un commento il metodo non è corretto a tutti. Personalmente evito sempre di programmare matematicamente, specialmente quando si tratta di logica. Quindi la mia soluzione sarebbe qualcosa come "se volessi sapere che il conteggio è uno, quindi contalo e confrontalo con il numero uno".

Eccolo:

public static bool OneIsSet(Type enumType, byte value) 
    { 
     return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1; 
    } 

    public static bool OneIsSet(Type enumType, int value) 
    { 
     return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1; 
    } 

E lo si può utilizzare per il vostro tipo foo in questo modo:

var toReturnFalse = (byte)(foo.Flag1 | foo.Flag2); 
    var toReturnTrue = (byte)foo.Flag1; 
    var trueWillBeReturned = OneIsSet(typeof(foo), toReturnTrue); 
    var falseWillBeReturned = OneIsSet(typeof(foo), toReturnFalse); 

Credo che questo metodi potrebbero essere scritti in modo più generico utilizzando Generics e tipo metodi di manipolazione. Tuttavia ho incluso i metodi per i tipi di base più comuni per enumerazioni int e byte. Ma potresti anche scrivere lo stesso per brevi e altri tipi. Inoltre puoi semplicemente inserire il codice nel tuo codice. È solo una riga di codice.

Anche utilizzando questo metodo è possibile vedere se il numero di flag di serie è due o più. Il codice qui sotto restituisce true se il conteggio dei flag set è uguale a 'n'.

Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == n; 
Problemi correlati