miércoles, 14 de mayo de 2014

Enumeraciones en C# - Parte 3

Tabla de Contenido

0. Introducción
1. ¿Qué son las Banderas (Flags)?
2. ¿Banderas en Enumeraciones?
2.1 El atributo [Flags]
2.2 Combinación de miembros de una enumeración
2.3 Otras operaciones interesantes
2.4 Notas importantes
3.5 Ejemplos
4. Conclusiones
5. Glosario
5. Literatura & Enlaces

0. Introducción

Esta es la tercera parte acerca de enumeraciones en C#. Vamos a explorar varias de las operaciones a nivel de bits sobre los enums. Aprenderemos que este tipo de operación facilita la combinación de valores de una enumeración como una colección: esto simplifica el número de constantes a declarar. Presentaré hasta 4 ejemplos para ilustrar esta interesante capacidad: días de la semana, los bordes de un cuadrado, ficha de contacto, y los colores de una paleta de colores.



Artículos de la serie:



Parte 1 - Introducción a la enumeraciones en C#

Parte 2 - Operaciones de las enumeraciones
Parte 3 - Valores bandera en las enumeraciones
Parte 4 - Operadores de las enumeraciones
Parte 5 - Casos de seguridad de tipos

1. ¿Qué son las Banderas (Flags)?

Podemos hacer una traducción arbitraria de Flags a español como 'Banderas'. Bueno, en particular en el lenguaje C#, este concepto facilita la conjugación (combinación) de valores predefinidos (las constantes o miembros de la enumeración). Estas combinaciones serán nuevos valores derivados de los originales, es decir, que a partir de una definición simple de constantes podemos obtener nuevas constantes. Esto lo podríamos ejemplificar, de forma natural, con lo que ocurre con los tres colores esenciales: rojo (), verde (), y azul ():

 + =
  = 
  +  =  (Blanco)

Podríamos seguir generando combinaciones según sea necesario.

Otro ejemplo en la asignación de atributos a archivos. Los modos de acceso:
  • Lectura
  • Escritura
  • Ejecución
Este modelo funciona correctamente en los sistemas operativos basados en el kérnel Linux. Para determinar los atributos de un archivo de usuario o de sistema, se combinas estos tres valores (banderas, para el caso que nos corresponde). Así:
  • Lectura [X], Escritura [-], Ejecución [-]
  • Lectura[X], Escritura[X], Ejecución [-]
  • Lectura[-], Escritura[-], Ejecución [X]
Tengamos en cuenta que pudimos generar otras tres combinaciones a partir de las básicas definidas arriba. (Desde luego se podrían generar otras más).

2. Banderas en Enumeraciones

Esta operación de combinación de constantes o miembros de enumeración es posible efectuarla en C#. Sin embargo, hay que tener en cuenta este par de recomendaciones (~reglas) en su definición [1]:
  • Los miembros de la enumeración deben tener un valor asignado.
  • El valor asignado debe ser un número de potencia de dos.
En las siguientes subsecciones veremos la definición, uso, y varios ejemplos.

2.1 El atributo [Flags]

El atributo [Flags] permite especificar que una enumeración va a ser tratada como un cambio en términos de bits. Esta representación es la que permite representar diferentes estados o banderas.

Este atributo se pone por encima de la declaración de la enumeración. De esta manera:

Ejemplo abstracto:

[Flags]
{modificador de acceso} enum {Nombre de la enumeración}
{
// conjunto de miembros
}

Ejemplo particular:

[Flags]
public enum Bordes
{
  Ninguno = 0,
Izquierdo = 1,
Derecho = 2,
Superior = 4,
Inferior = 8
}

Los 5 miembros de la enumeración (i.e., NoneIzquierdoDerechoSuperior, e Inferior) tienen asignados valores explícitos. Estos valores corresponden con potencias de dos: 0, 2^0 = 1, 2^1 = 2, 2^2 = 4, 2^3 = 8, respectivamente.

2.2 Combinación de miembros de una enumeración

Ya hemos dicho que en C# el atributo [Flags] permite asignar de forma implícita un valor binario a las miembros de una enumeración. Ahora, para realizar operaciones de bit-a-bit (bitwise -cfr. Operadores Bitwise (Bit a Bit) en C#-) usamos los operadores:

  • | (OR inclusivo), y
  • & (AND)
Sigamos con el ejemplo de la sección anterior (i.e., enumeración Bordes):

Bordes derechoIzquierdo = Bordes.Derecho | Bordes.Izquierdo;

El valor asignado a la bandera derechoIzquierdo es:

Bordes.Derecho = 2 = 2^1 = 00000010
Bordes.Izquierdo = 1 = 2^0 = 00000001

Aplicamos la operación OR (inclusivo):

00000010 |
00000001
=
00000011

Ahora si queremos saber si una combinación posee un de las definiciones básicas de la enumeración, utilizamos el operador AND:

derechoIzquierdo & Bordes.Derecho

En matemática binaria tenemos:

00000011 &
00000010
=
00000010

Con un instrucción de selección if podemos utilizar un operador de igualdad. De este modo:

if ((derechoIzquierdo & Bordes.Derecho) !=0)
{
Console.WriteLine("Incluye el lado derecho.");
}

Por otro lado, el valor de la variable derechoIzquierdo es igual a:

Console.WriteLine(derechoIzquierdo.ToString()); // Salida: "Derecho, Izquierdo"

2.3 Otras operaciones interesantes

Podemos alternar el valor de una variable tipo enum -Bordes- aplicando uno de los operadores compuestos:

Bordes borde = Bordes.Derecho;
borde |= Bordes.Izquierdo;
Console.WriteLine(borde == (Bordes.Derecho | Bordes.Izquierdo)); // Salida: True

Así mismo:

borde ^= Bordes.Izquierdo;
Console.WriteLine(borde); // Salida: Derecho

Con la penúltima instrucción estamos alternando valores. Con matemática binaria:

00000001 ^
00000011
=
00000010

2.4 Notas importantes

Desde [1] anuncian:
By convention, a combinable enum type is given a plural rather than singular name.
Por otro lado [ídem], en la definición de una enumeración se puede incluir miembros producto de una combinación:

[Flags]
public enum Bordes
{
Ninguno = 0,
Izquierdo = 1,
Derecho = 2,
Superior = 4,
Inferior = 8,
DerechoIzquierdo = Derecho | Izquierdo,
SuperiorInferior = Superior | Inferior,
Todos = DerechoIzquierdo | SuperiorInferior
}

3. Ejemplos

3.1 CRUD

CRUD (Acrónimo de Create, Read, Update, y Delete). Para este conjunto de operaciones vamos a definir una enumeración que definirá las combinaciones de permisos que tiene un usuario sobre una base datos o tabla.

Archivo Crud.cs:



Compilación:


  1. csc /target:exe Crud.cs

> Prueba de ejecución.

Resultado:


Permisos para infzero: Crear, Actualizar

3.2 Días de la semana

Ahora veamos una enumeración con los días de la semana. Esta enumeración nos puede ser de  utilidad para, por ejemplo, un sistema de calendarización que admita la repetición de tareas o eventos programados; o simplemente, la combinaciones estándar: fines de semana, o días laborables, &c.

Archivo DiasSemana.cs:

Compilación:

  1. csc /target:exe SerializacionJson.cs

> Prueba de ejecución.

Resultado:

Resumen del evento:
 Nombre evento: Escribir acerca de enumeraciones en C#.
 Fecha y hora evento: 5/22/2014 1:17:19 PM
 Día(s) evento: Lunes, Miercoles, Viernes

4. Conclusiones

La combinación de miembros de una enumeración nos puede representar un ahorro de tiempo programático en la declaración y uso de este tipo de construcciones en el lenguaje C#. Vimos que es posible trabajar con una representación binaria de los valores asignados a los miembros de una enumeración: bit-a-bit (bitwise).

5. Glosario

  • Binario
  • Bit-a-bit
  • Bitwise
  • Combinación
  • Matemática

6. Literatura & Enlaces

[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2]: What does the [Flags] Enum Attribute mean in C#? - Stack Overflow - http://stackoverflow.com/questions/8447/what-does-the-flags-enum-attribute-mean-in-c
[3]: C# Enum Flags Attribute - http://www.dotnetperls.com/enum-flags
[4]: banderas en c# | Really Develop - http://josebgd.wordpress.com/tag/banderas-en-c/
[5]: FlagsAttribute Class (System) - http://msdn.microsoft.com/en-us/library/system.flagsattribute(v=vs.110).aspx
[6]: Operadores Bitwise (Bit a Bit) en C# | OrtizOL - Experiencias Construcción Software (xCSw) - http://ortizol.blogspot.com/2013/07/operadores-bitwise-bit-bit-en-c.html


J

1 comentario:

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.