Monday, February 14, 2011

.NET - Valores enum como flags de bits

Una vez que entendemos el uso de los ENUM pensamos que eso es todo lo que hay. Sin embargo, en algún momento caemos en alguna instrucción o con algún componente que parece sumarlos, restarlos, y combinarlos con operadores que no conocíamos. Bueno, este es un conocimiento que un semi-senior no puede desconocer, y si eres Senior y todavía no lo conoces entonces preocúpate un poco :).


A veces nos gustaría usar un enum como si fueran flags. Es decir, que hipotéticamente tendríamos la colección de ceros "0000" y cada cero es un switch, donde un 1 representa encendido. Por ejemplo, 0101 significa que encendimos los flags 2 y 4. Esto podría ser útil para reemplazar variables booleanas en algunos casos.


Arranquemos con enum común:


public enum ExportTypes
{

   None,
   Text,
   Excel,
   CSV,
   JSon,
   XML
}


Copado. Representa diferentes tipos de exportación para algo de nuestra aplicación. Sin embargo, teniéndolo de esta forma sólo podemos tener un tipo de exportación a la vez. ¿Qué hay si quiero hacer tanto JSON como XML a la vez? ¿Realmente es necesario que ejecute una rutina dos veces con parámetros diferentes? Imaginen sino, un servicio de Windows que recibe por MSMQ mensajes XML para procesar exportaciones. En este caso recibiría información y el tipo de exportación JSON. Y luego para hacerlo con XML lo tendríamos que mandar todo de nuevo. Pues no, podemos mezclar los enum utilizando el atributo Flags.


[Flags]
public enum ExportTypes
{

   None,
   Text,
   Excel,
   CSV,
   JSon,
   XML
}


Vaya. ¿Qué nos cambia esto? Ahora los valores de cada valor de enum son como siguen:


None = 0
Text = 1
Excel = 2
CSV = 4
JSon = 8
XML = 16


Noten como cada valor 2 a la N, donde N es la posición del valor en el enum, por decirlo de una forma. Lo mismo ocurre en un grupo de bits 00000. El bit de la derecha vale 1 y el de la izquierda de todo vale 16. No hay bit que represente el cero. Entonces si queremos tener TEXT y CSV tenemos que hacer algo como 00101.


Ya hemos declarado el enum con el atributo flags. Veámos cómo lo podemos utilizar.


ExportExecution.ExportTypes = ExportTypes.Text | ExportTypes.Excel;


Utilizamos el operador | que es un OR. Esto quiere decir que ahora nuestra variable ExportTypes de una hipotética clase ExportExecution vale 00011. Entonces en nuestra aplicación podremos preguntar si están en 1 alguno de esos bits.


if(this.ExportTypes & ExportTypes.Text == ExportTypes.Text) {


Esto se fija que tengamos el bit de Text seteado. Lo mismo podemos hacer para cualquier valor del enum.


Nota: El debugger de .NET no nos mostrará los diferentes valores, sino el menor de los activados. En este caso sólo nos mostraría Text.


Bastante simple no? Finalmente algo a tener en cuenta es que el primer valor del enum, en este caso None, siempre nos dará true, porque el valor 0 no tiene bit que le represente. Por eso hemos nombrado como None este tipo de exportación.

No comments:

Post a Comment