2012-01-21 8 views
32

Solo quiero saber si se ha configurado exactamente una bandera enum, no cuáles. Mi pensamiento actual es comprobar si es un poder de 2. ¿Hay alguna manera mejor incorporada a los tipos enum?¿Cómo verifico si hay más de una bandera enum configurada?

[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

Parece bastante simple, sí. ¿Por qué no hacerlo de esa manera? – Groo

+2

No coloque un prefijo en sus títulos con "C#:" y tal. Para eso son las etiquetas. –

+0

¿Por qué tengo la sensación de que esta es una pregunta de "mira mi solución" disfrazada de pregunta ... –

Respuesta

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

@MarkHall en.NET si se establece más de un indicador, la representación de cadena de la enumeración es una lista delimitada por comas. –

+1

@MarkHall El atributo Flags lo hace mostrar los nombres de valores individuales separados por comas. Puedes seguir y probarlo. – itsme86

+0

Me corresponde corregido –

7

Si la enumeración no define combinaciones explícitas de banderas, sólo puede comprobar si el valor se define en la enumeración:

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

¿Por qué el voto a favor? –

+0

+1: Esto funciona, incluso si la enumeración define explícitamente combinaciones ('enum Foo {Ninguno = 0, A = 1, B = 2, C = 4, AB = A | B, BC = B | C, Todo = A | B | C,} '). Especificar una de las combinaciones predefinidas ('Enum.IsDefined (typeof (Foo), Foo.A | Foo.B)') arrojará 'true': de hecho es un valor definido. –

+0

@NicholasCarey, sí, devolverá true para AB, pero AB tiene más de un bit configurado ... El OP quiere saber si hay más de un bit configurado, no si el valor está definido. –

52

Es una operación poco!

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

Las comprobaciones de los estados si el valor de myFoo no es potencia de dos. O, viceversa, la instrucción (myFoo & (myFoo -1)) == 0 comprueba la potencia de dos. La idea es que solo los valores de bandera única serán potencia de dos. Establecer más de un indicador dará como resultado una potencia no de dos valores de myFoo.

Más información se puede encontrar en esta respuesta a una pregunta similar: https://stackoverflow.com/a/1662162/2404788.

Para obtener más información acerca de las operaciones de bits van a http://en.wikipedia.org/wiki/Bitwise_operation

+3

+1, solución muy elegante! –

+0

@Guido Gran solución. ¿Puedes agregar alguna explicación, por favor? – Shimmy

+0

Gracias @Shimmy. He agregado una explicación básica. Espero que sea útil –

0

Como Jacob explica en un comentario de su método no es correcto en absoluto. Personalmente siempre evito programar matemáticamente, especialmente cuando se trata de lógica. Entonces, mi solución sería algo así como "si quisiera saber que el recuento es uno, cuenten y compárenlo con el número uno".

Aquí está:

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

Y usted puede utilizarlo para su tipo foo como esto:

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

Creo que estos métodos pueden ser escritos de una manera más genérica utilizando los genéricos y el tipo métodos de manejo Sin embargo, incluí los métodos para los tipos de base más comunes para enumeraciones que son int y byte. Pero también puedes escribir lo mismo para abreviar y otros tipos. También puede insertar el código en su código. Es solo una linea de codigo

También utilizando este método, puede ver si el número de banderas establecidas es dos o más. El código siguiente devuelve verdadero si el recuento de banderas establecidas es igual a 'n'.

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