2011-09-19 18 views
7

suponga que tiene enum MyEnum {A = 0, B = 1, C = 2, D = 4, E = 8, F = 16};C#: ¿La mejor manera de comparar con un conjunto de valores de Enum?

En algún momento usted tiene una función que compruebe una instancia de MyEnum y devolver verdadero si es C, D o F

bool IsCDF(MyEnum enumValue) 
{ 
    return //something slick 
} 

Recuerdo que había una cierta Manera muy hábil para hacer cambios de bit y preformar esta operación que se lee mucho mejor que un montón de declaraciones terciarias, pero por mi vida no puedo recordar de qué se trata.

¿Alguien sabe?

+0

http://stackoverflow.com/questions/93744/most-common-c-bitwise-operations/417217#417217 –

Respuesta

15

Si usted hace un [Banderas] enumeración, se puede asignar un valor poco diferente (1, 2, 4, 8, 16 ...) para cada valor enumerado. Luego puede usar una operación bit a bit para determinar si un valor es uno de un conjunto de valores posibles.

lo tanto, para ver si es C, D o F:

bool IsCDF(MyEnum enumValue) 
{ 
    return((enumValue & (MyEnum.C | MyEnum.D | MyEnum.F)) != 0); 
} 

Tenga en cuenta que esto no va a funcionar para un valor de 0 (en el ejemplo, 'A'), y debe estar cuidadoso de que todos los valores de enum se resuelvan en valores de bit únicos (es decir, potencias de dos diferentes de cero).

Las ventajas de este enfoque son:

  • se suele tomar una sola instrucción de la CPU para ejecutar, mientras que haciendo tres separada "si" verificaciones tendrán en 3 o más instrucciones (dependiendo de la plataforma de destino).
  • puede pasar el conjunto de valores que desea probar con como un valor de enumeración (un entero) en lugar de tener que utilizar listas de valores de enumeración.
  • Puede hacer muchas otras cosas útiles con operaciones bit a bit, que serían torpes y lentas con los enfoques numéricos/comparativos ordinarios.
+0

Sí, tengo un bloc de notas y algo similar. Quería usar esto con ConnectionState de BCL, que lamentablemente tiene ConnectionState.Cerrado = 0 - Podría subir todo a una potencia de dos, pero estamos dejando el rango de 'ser resbaladizo'. –

+0

Aunque, si la lista Estoy comprobando contra no contiene un 0, entonces se debe evaluar siempre a falso de todos modos ... –

+0

Sí, yo soy 2 años de retraso - pero yo aconsejaría contra esto, porque es peligroso en el largo correr. No muy legible, no muy limpio. – FrankB

0
return (enumValue & MyEnum.C == MyEnum.C) 
     || (enumValue & MyEnum.D == MyEnum.D) 
     || (enumValue & MyEnum.F == MyEnum.F); 
+1

No creo que el OP esté interesado en esta forma de verificarlo. –

+0

Sí, esto sigue siendo básicamente si las declaraciones, simplemente no verdadero/falso –

5

que posiblemente haría uso de Unconstrained Melody como una forma de mantener las cosas ordenadas:

if (value.HasAny(MyEnum.C | MyEnum.D | MyEnum.E)) 
{ 
    ... 
} 

probablemente me extraer el bit "C, D o E" en una constante llamada - posiblemente en la enumeración sí, si tuviera significado:

1

Tal vez esta clase de extensión es muy útil para usted:

public static class Flags 
{ 
    /// <summary> 
    /// Checks if the type has any flag of value. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static bool HasAny<T>(this System.Enum type, T value) 
    { 
     try 
     { 
      return (((int) (object) type & (int) (object) value) != 0); 
     } 
     catch 
     { 
      return false; 
     } 
    } 

    /// <summary> 
    /// Checks if the value contains the provided type. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static bool Has<T>(this System.Enum type, T value) 
    { 
     try 
     { 
      return (((int)(object)type & (int)(object)value) == (int)(object)value); 
     } 
     catch 
     { 
      return false; 
     } 
    } 

    /// <summary> 
    /// Checks if the value is only the provided type. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static bool Is<T>(this System.Enum type, T value) 
    { 
     try 
     { 
      return (int)(object)type == (int)(object)value; 
     } 
     catch 
     { 
      return false; 
     } 
    } 

    /// <summary> 
    /// Appends a value. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static T Add<T>(this System.Enum type, T value) 
    { 
     try 
     { 
      return (T)(object)(((int)(object)type | (int)(object)value)); 
     } 
     catch (Exception ex) 
     { 
      throw new ArgumentException(
       string.Format(
        "Could not append value from enumerated type '{0}'.", 
        typeof(T).Name 
        ), ex); 
     } 
    } 

    /// <summary> 
    /// Appends a value. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static void AddTo<T>(this System.Enum type, ref T value) 
    { 
     try 
     { 
      value = (T)(object)(((int)(object)type | (int)(object)value)); 
     } 
     catch (Exception ex) 
     { 
      throw new ArgumentException(
       string.Format(
        "Could not append value from enumerated type '{0}'.", 
        typeof(T).Name 
        ), ex); 
     } 
    } 

    /// <summary> 
    /// Removes the value. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static T Remove<T>(this System.Enum type, T value) 
    { 
     try 
     { 
      return (T)(object)(((int)(object)type & ~(int)(object)value)); 
     } 
     catch (Exception ex) 
     { 
      throw new ArgumentException(
       string.Format(
        "Could not remove value from enumerated type '{0}'.", 
        typeof(T).Name 
        ), ex); 
     } 
    } 

    /// <summary> 
    /// Removes the value. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="type"></param> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static void RemoveFrom<T>(this System.Enum type, ref T value) 
    { 
     try 
     { 
      value = (T)(object)(((int)(object)type & ~(int)(object)value)); 
     } 
     catch (Exception ex) 
     { 
      throw new ArgumentException(
       string.Format(
        "Could not remove value from enumerated type '{0}'.", 
        typeof(T).Name 
        ), ex); 
     } 
    } 
} 
17
bool IsCDF(MyEnum enumValue) 
{ 
    return new[]{MyEnum.C, MyEnum.D, MyEnum.F}.Contains(enumValue); 
} 
Cuestiones relacionadas