domingo, 11 de mayo de 2014

Enumeraciones en C# - Parte 1

Tabla de Contenido

0. Introducción
1. Introducción a la Enumeraciones en C#
1.1 ¿Qué es una enumeración
1.2 Ejemplos de enumeraciones
1.3 ¿Cómo declarar una enumeración en C#
1.4 Uso de enumeraciones desde código cliente
2. Conversión de Enumeraciones
2.1 Conversión explícita entre enumeraciones
3. Buenas Prácticas en Enumeraciones
4. Conclusiones
5. Glosario
6. Literatura & Enlaces

0. Introducción

A lo largo de este artículo vamos a descubrir el concepto de enumeraciones en C#. Veremos su utilidad para la especificación de constantes: días de las semanas, meses del año, colores, coordenadas, límites en rangos de valores, y cualquier conjunto de valores que opten por ser constantes a lo largo del ciclo de vida de una aplicación. Introduciré varios ejemplos para concretar los conceptos que veremos a lo largo de las 5 partes que integrarán esta serie:

Parte 1 - Introducción a la enumeraciones en C#
Parte 2 - Operaciones de las enumeraciones
Parte 3 - Valores centinela de las enumeraciones
Parte 4 - Operadores de las enumeraciones
Parte 5 - Casos de seguridad de tipos

1. Introducción a las Enumeraciones en C#

1.1 ¿Qué es una enumeración?

Una enumeración no es más que un conjunto de constantes lógicamente relacionadas. Estas constantes se agrupan en un tipo con un identificador que las lógica por su lógica de aplicación, es decir, por la naturaleza de valores que representan: serie de valores constantes (días de la semana, meses del año, colores de una paleta RGB, etc.).

La agrupación lógica de valores constantes son considerados una construcción programática para mantener la consistencia sobre el conjunto de valores posibles que puede desplegarse, por ejemplo, en un menú, los argumentos permitidos en la instanciación de un objeto, en la invocación de un método, &c.

Con las enumeraciones nos podemos deshacer de los problemas de valores inconsistentes para operaciones programáticas definidas en los pasos de nuestros algoritmos que comprenden la lógica de negocios de nuestras soluciones software, la entrada desde un formulario en la interfaz gráfica de usuario, &c.

1.2 Ejemplos de enumeraciones

A continuación un listado de constantes tentativas para optar a enumeraciones:
  • Días de la semana:
    • Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado
  • Colores:
    • Negro, Blanco, Rojo, Verde, Azul, Amarillo, Morado, Plateado, Púrpura, Naranja, &c.
  • Meses del año:
    • Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre.
  • Coordenadas:
    • Este, Oeste, Sur, Norte, Noreste, Noroeste, Sureste, Suroeste.
  • Rango:
    • Mínimo, Máximo
  • Razas de perros:
    • Boxer, Briard, Caniche, Cane Corso, Doberman, Dálmata, Chow Chow, Komondor, Mastiff, Pastor Alemán, Pekinés, Pug, Spitz, &c.
  • Estados de una máquina:
    • Apagado, Encendido, Hibernando, Suspendido
  • Grado de importancia en agenda:
    • Ninguno, Trivial, Regular, Importante, Crítico
El listado puede extenderse infinitamente. La elección dependerá del modelo del mundo del problema que estemos implementando en nuestra solución. Sin embargo, se recomienda el uso de enumeraciones para crear agrupaciones lógicas de valores constantes para ser utilizadas a lo largo del proyecto y ganar reusabilidad de los tipos que definimos.

1.3 ¿Cómo declarar una enumeración en C#?

La construcción sintáctica (palabra reservada) para la declaración de enumeraciones en C# es enum [2]. En el siguiente código fuente C# se muestra un ejemplo abstracto de su uso:

{Modificador de acceso} enum {Nombre de la enumeración}
{
{Constante} [= {valor inicialización}] [, {otras constantes}]
}

Ejemplo particular:

public enum Bordes
{
Izquierdo,
Derecho,
Superior,
Inferior
}


Las constantes IzquierdoDerechoSuperior, e Inferior son todas de tipo por valor (Int32). Sin embargo, se puede especificar otro tipo por valor utilizando el operador de herencia e implementación : (dos puntos) para especificar el tipo de las constantes; de los cuales podríamos utilizar uno de los siguientes:
  • byte
  • sbyte
  • short
  • ushort
  • int
  • uint
  • long
  • ulong
A pesar de que char es un tipo por valor integrado, no está permitido para la especificación de tipos de constantes.

También es importante decir que el valor por defecto para la primera constante en la enumeración es cero (0), esto lo podemos alterar especificando un valor diferente. Así:

public enum Bordes
{
Izquierdo = 1,
Derecho,
Superior = 5,
Inferior
}

Hemos especificado valores arbitrarios para las constantes Izquierdo (1), y Superior (5), a las demás constantes se les asignará el valor siguiente de la serie. Entonces éstas quedan así:
  • Derecho = 2
  • Inferior = 6
Por otro lado, si el encabezado declarativo de la enumeración, es:

public enum Bordes : byte

A las constantes en la enumeración Bordes sólo se les puede asignar valores del tipo subyacente, es decir de byte: Rango: 0 a 255.

Nota desde [2]:
An enumerator cannot contain white space in its name.

1.4 Uso de enumeraciones desde código cliente

Archivo Ejemplo1Enum.cs:

En las líneas 20-29 declaramos la enumeraciones con las constantes de los días de la semana; desde Main obtenemos los valores numéricos asociados a dos constantes. Así:

int x = (int) Dias.Lunes;
int y = (int) Dias.Miercoles;

Para el primer caso, a x se le asignará el valor 1; y para la variable entera y el valor 3, le será asignado. (Más adelante veremos el uso de la conversión explícita entre constante de enumeración y tipos por valor).

>  Prueba de ejecución.

1.4.1 Instanciación de enumeraciones

La operación de instanciación la podemos llevar a cabo de la siguiente manera:

Tomemos la siguiente enumeración como ejemplo:

public enum EstadoLlegado
{
Retarado = -1,
ATiempo = 0,
Temprano = 1
}

En código cliente creamos instancias de EstadoLlegado de la siguiente forma:

EstadoLlegado estado1 = EstadoLlegado.ATiempo;

EstadoLlegado estado2 = (EstadoLlegado) 1; // Conversión explícita

EstadoLlegado estado3 = new EstadoLlegado(); // Valor por defecto 0

1.4.2 Otro ejemplo de uso de enumeraciones

Para el siguiente ejemplo cambiamos el tipo base de la enumeración por long. Aquí demostramos que el tipo de las constantes será, implícitamente, de ese mismo tipo. Lo anterior significa que los valores asignados a las constantes deberá ser una literal con el especificador de entero de 64 bits, es decir, L.

Archivo Ejemplo2Enum.cs:

En las líneas 20-24 se declara la enumeración Rango con tipo base long. En la línea 22 se asigna a la constante Maximo la literal numérica 21474483648L (valor explícito long), de forma similar para la constante Minimo (línea 23).

> Prueba de ejecución.

2. Conversiones de Enumeraciones

Las conversiones de enumeraciones se puede realizar en dos direcciones, es decir:
  • Enumeración a tipo por valor, y
  • Tipo por valor a enumeración
Por ejemplo, siguiendo con la enumeración Bordes, podemos realizar los siguientes tipos de conversiones:

// Conversión de constante de enumeración a entero a Int32
int valorDeConstante = (int) Borde.Izquierdo;
// Conversión de entero de 32 bits a constante de enumeración
Borde borde = (Borde) valorDeConstante;

Otro caso importante a considerar es la literal numérica 0 (cero):

Bordes b = 0; // No requiere conversión

Esta asignación nos permite crear una constante de la enumeración Bordes, sin requerir ninguna conversión. Así mismo:

if (b == 0)

tampoco lo requiere por la naturaleza especial de la literal numérica 0 (cero) en las enumeraciones. [Nota:Recomiendo leer las sugerencias de buenas prácticas en la sección 3.]

2.1 Conversión explícita entre enumeraciones

Podemos ejecutar conversiones explícitas entre las constantes de enumeraciones. Veamos este ejemplo práctico:

La enumeración Bordes que hemos utilizado previamente:

public enum Bordes
{
Izquierdo,
Derecho,
Superior,
Inferior
}

Ahora la enumeración de alineación horizontal, AlineacionHorizontal:

public enum AlineacionHorizontal
{
Izquierda : Borde.Izquierdo,
Derecha : Borde.Derecho,
Centro
}

Observemos que hemos asignado a dos de las constantes de AlineacionHorizontal (i.e., Izquierda, y Derecha) los valores de las constantes de BordesBorde.Izquierdo y Borde.Derecho, respectivamente.

Ahora pongamos en acción estas enumeraciones desde código cliente:


En las líneas 21-27, y 29-34 se declaran las enumeraciones Bordes y AlineacionHorizontal, respectivamente. En el código cliente (líneas 36-53) tenemos las dos siguientes conversiones:

AlineacionHorizontal izquierda = (AlineacionHorizontal) Bordes.Izquierdo;
izquierda = (AlineacionHorizontal) (int) Bordes.Izquierdo;

En la primera sentencia (línea 38 en el archivo ConversionExplicitaEnums.cs) especificamos el operador de casting explícito -(AlineacionHorizontal)- para crear una enumeración de tipo AlineacionHorizontal a partir de una de la constante Bordes.Izquierdo.

Para la segunda sentencia ocurre lo siguiente:
  1. Pasamos a entero de 32 bits (int) el valor de la constante Bordes.Izquierdo.
  2. El valor entero de 32 bits es convertido de forma explícita -(AlineacionHorizontal)-.

Resultado:
Resultado conversión explícita de enumeraciones.
Figura 1. Resultado conversión explícita de enumeraciones.

3. Buenas Prácticas en Enumeraciones

Desde [1] nos sugieren que sigamos las siguientes buenas prácticas en la manipulación de enumeraciones en C#. (Extracto literal):

  • If you have not defined an enumeration member whose value is 0, consider creating a None enumerated constant. By default, the memory used for the enumeration is initialized to zero by the common language runtime. Consequently, if you do not define a constant whose value is zero, the enumeration will contain an illegal value when it is created.
  • If there is an obvious default case that your application has to represent, consider using an enumerated constant whose value is zero to represent it. If there is no default case, consider using an enumerated constant whose value is zero to specify the case that is not represented by any of the other enumerated constants.
  • Do not specify enumerated constants that are reserved for future use.
  • When you define a method or property that takes an enumerated constant as a value, consider validating the value. The reason is that you can cast a numeric value to the enumeration type even if that numeric value is not defined in the enumeration.

4. Conclusiones

Hemos comprendido el concepto de las enumeraciones (desde un punto de vista genérico: primera parte de la sección) y su concreción en el lenguaje de programación C#: definición, instanciación, conversión (explícita), y uso en asignación. Al final exploramos algunas sugerencias respecto a buenas prácticas en la manipulación de enumeraciones en C#. En la siguiente parte trataremos acerca de las operaciones sobre enumeraciones.

5. Glosario

  • Buena práctica
  • Casting
  • Conversión
  • Enumeración
  • Enums
  • Explícita

5. 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]: enum (C# Reference) - http://msdn.microsoft.com/en-us/library/sbbt4032.aspx
[3]: Enum Class (System) - http://msdn.microsoft.com/en-us/library/system.enum%28v=vs.110%29.aspx
[4]: C# Enum Examples - http://www.dotnetperls.com/enum
[5]: coding style# have their own file? - Stack Overflow - http://stackoverflow.com/questions/2282976/should-enums-in-c-sharp-have-their-own-file
[6]: byte (C# Reference) - http://msdn.microsoft.com/en-us/library/5bdb6693.aspx
[7]: Enumeration, the free encyclopedia - https://en.wikipedia.org/wiki/Enumeration
[8]: Enumerated type, the free encyclopedia - https://en.wikipedia.org/wiki/Enumerated_type


J

No hay comentarios:

Publicar un comentario

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