2010-09-16 8 views
10

Al utilizar Enums con campos de bits:¿Hay alguna otra forma de probar los campos de bits Enum?

enum ReallyBigEnum { FirstChoice = 0x01, AnotherOption = 0x02 } 
    ReallyBigEnum flag = ReallyBigEnum.FirstChoice | ReallyBigEnum.AnotherOption; 

el código utilizado para probar los bits es:

if((flag & ReallyBigEnum.AnotherOption) == ReallyBigEnum.AnotherOption) { ... } 

que parece verbosa y propenso a errores debido a la necesidad de repetir el bit siendo probado.

Sería agradable si había alguna manera de decir:

if(flag.IsSet(ReallyBigEnum.AnotherOption)) { ... } 

pero enumeraciones no son compatibles con los métodos de instancia. Por lo tanto, he intentado una función de plantilla:

class Enums 
    { 
     public static bool IsSet<T>(T flag, T bit) { return (flag & bit) == bit; } 
    } 

pero el código para probar los bits a continuación, tiene el siguiente aspecto:

if(Enums.IsSet<ReallyBigEnum>(flag, ReallyBigEnum.AnotherOption)) { ... } 

lo cual es mucho para escribir. Luego trató de acortarlo:

class Enums 
    { 
     public static bool IsSet(int flag, int bit) { return (flag & bit) == bit; } 
    } 

pero luego se va a emitir cada valor a su tipo base como esto:

if(Enums.IsSet((int)flag, (int)ReallyBigEnum.AnotherOption)) { ... } 

que es también un dolor de código y pierde el beneficio de la comprobación de tipos .

Se podría escribir la misma función para usar los parámetros 'objeto', pero luego debería probarse el tipo de objeto y el tipo de base subyacente.

Por lo tanto, estoy atascado con la forma estándar y redundante en la parte superior.

¿Alguien tiene otras ideas sobre una manera limpia y simple de probar los campos de bits Enum?

Much Thanks.

Respuesta

6

Hasta .Net 3.5 esta es su única opción. En .Net 4.0 hay un método HasFlag en la enumeración.

+0

El método HasFlag() es la solución perfecta, por supuesto. ¡Gracias! Desafortunadamente, nuestro entorno de desarrollo todavía usa .NET 2.0. –

2
if((flag & ReallyBigEnum.AnotherOption) != 0) { ... } 

ACTUALIZADO:

Lo anterior, obviamente, sólo funcionan si se está probando un solo bit. Si desea probar varios bits, se requiere algo más, dependiendo de si está buscando todos los bits o cualquier bit.

Testing que cualquiera de un conjunto de bits se establece

Para este caso, sólo tiene que utilizar una variante de la versión de un solo bit.

if((flag & (ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption)) != 0) { ... } 

Pruebas de que todos un conjunto de bits se fija

Para este caso a achive claridad y fiabilidad, Sugiero crear una constante que contiene todos los bits.

const int ReallyBigEnum WickedAwesomeOptions = ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption; 
... 
if (flag & WickedAwesomeOptions == WickedAwesomeOptions) { ... } 

Parte de la redundancia sigue presente, pero no es frágil ni confusa, y es fácil de mantener.

Si la combinación de bits se aplica ampliamente, puede agregarla a la enumeración en sí.

[Flags] 
enum ReallyBigEnum 
{ 
    FirstOption = 1, 
    AnotherOption = 2, 
    WickedAwesomeOptions = FirstOption | AnotherOption, 
} 
.... 
if (flag & ReallyBigEnum.WickedAwesomeOptions == ReallyBigEnum.WickedAwesomeOptions) { ... } 
+0

Esto elimina la redundancia, pero solo funcionará si todas las banderas son bits individuales. Las banderas compuestas con múltiples bits pueden devolver falsos positivos. –

+0

@Chris C. - Claro que solo funciona con banderas de un solo bit. Eso es exactamente lo que la pregunta está pidiendo. Ninguna parte de la pregunta pregunta sobre verificar múltiples bits. –

+0

@Chris C. - Modifiqué la respuesta para abordar esta nueva pregunta. –

2
/// <summary> 
/// Taken from https://stackoverflow.com/questions/9033/hidden-features-of-c/407325#407325 
/// instead of doing (enum & value) == value you can now use enum.Has(value) 
/// </summary> 
/// <typeparam name="T">Type of enum</typeparam> 
/// <param name="type">The enum value you want to test</param> 
/// <param name="value">Flag Enum Value you're looking for</param> 
/// <returns>True if the type has value bit set</returns> 
public static bool Has<T>(this System.Enum type, T value) 
{ 
    return (((int)(object)type & (int)(object)value) == (int)(object)value); 
} 

Aquí es un método de extensión Tomé del uso above link

:

MyFlagEnum e = MyFlagEnum.First | MyFlagEnum.Second; 
if(e.Has(MyFlagEnum.First)) 
{ 
    // Do stuff 
} 
+0

Oh, pero usa .NET 2, entonces no hay métodos de extensión ... – PostMan

+0

Muy buena solución. La documentación dice que para C#, los métodos de extensión son tan eficientes como los métodos de clase originales. Los métodos de extensión se introdujeron en .NET v3.0. Este código hace una suposición sobre el tamaño de Enum que también puede basarse en enteros sin signo y largos. –

+1

Si el molde se cambió a: valor (largo) (objeto) ¿funcionaría para todos los tipos de enteros? –

Cuestiones relacionadas