domingo, 11 de mayo de 2014

Enumeraciones en C# - Parte 2

Tabla de Contenido

0. Introducción
1. Clase Enum
2. Conversiones
2.1 El método ToObject
2.2 El método IsDefined
2.3 Los métodos ChangeType (Convert) y GetUnderlyingType (Enum)
3. Transformación (Parsing) de Valores de una Enumeración
4. Formateo de Valores de una Enumeración
5. Iteración de Miembros de una Enumeración
6. Conclusiones
7. Glosario
8. Enlaces & Literatura

0. Introducción

En la primera parte de la serie de artículos de Enumeraciones en C#, hicimos una introducción de los conceptos generales y concretos de las enumeraciones: definición abstracta de una enumeración, declaración, instanciación, conversión de enumeraciones en el lenguaje C#. Ahora llega la oportunidad de definir varias operaciones interesantes sobre las enumeraciones. Estas operaciones, como veremos, están definidas en una clase base: Enum.

Artículos de la 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. Clase Enum

La clase Enum [2] es la superclase de todas las enumeraciones integradas en el Framework .NET y las propias creadas por un programador. Esta clase posee los métodos que heredan todas las enumeraciones para llevar a cabo operaciones de conversión, generación de valores y nombres, parsing, formateo de de los valores de las enumeraciones, iteración de los miembros de una enumeración, entre otras más.

A lo largo de este artículo nos concentramos en explicar varias de estas operaciones para sofisticar nuestro entendimiento de estas estructuras (construcciones) del lenguaje C#.

2. Conversiones

Podemos convertir miembros de una enumeración desde y hacia el tipo subyacente de la enumeración, es decir: asumamos que el tipo base de la enumeración es long, luego, las conversiones de miembros de la enumeración y los tipos a asignar a éstos (los miembros) deben ser valores enteros de 64 bits. Por ejemplo:

enum Rango : long
{
Maximo = 21474483648L,
Minimo = 255L
}

Desde código cliente podemos realizar las siguientes operaciones de conversión:

long valor = 255L;
Rango rango = (Rango) valor;

Hemos utilizado el operador de conversión (casting) explícita (Rango) para convertir el valor entero long almacenado en la variable valor. en la variable rango de tipo Rango.

2.1 El método ToObject

El método sobrecargado ToObject [3] nos permite realizar conversiones desde un valor entero a uno de los miembros de una enumeración. En la Figura 1 se muestra la lista sobrecargada de ToObject:
Versiones sobrecargadas del método ToObject
Figura 1. Versiones sobrecargadas del método ToObject [3].
En el par de líneas de código que vienen a continuación, hacemos uso de la versión sobrecargada ToObject(Type, Int64) [4] para convertir un entero de 64 bits (long) a uno de los valores admitidos por la enumeración Rango. Así:

long valor = 255L;
Rango minimo = (Rango) Rango.ToObject(typeof(Rango), valor);

El método ToObject(Type, Int64) retorna un valor de tipo Object, de ahí que sea necesario realizar la conversión explícita con (Rango) (segunda línea).

2.2 El método IsDefined

Quizás en la lógica de nuestra aplicación se intente pasar o asignar un valor (a través de una conversión) que no esté definido para los miembros de una enumeración. Para atacar este problema, el método IsDefined [5] permite averiguar si un miembro (o constante) en una enumeración existe.

Aprendamos de su utilidad con este ejemplo ejecutable:


En la línea 44 se pasa como argumentos al método IsDefined: el tipo de la enumeración, junto el valor entero a convertir. La evalucación de Enum.IsDefined(typeof(EstadoLlegada), valor) generará un valor lógico booleano que indica si el valor de la variable valor se halla asignado en uno de los miembros de la enumeración.

> Prueba de ejecución ([Nota: Gracias al Ideone [14] por hacer esto posible.]).

Resultado:

Equivalencia de -3 en `EstadoLlegada` es Desconocido
Equivalencia de -1 en `EstadoLlegada` es Retardado
Equivalencia de 0 en `EstadoLlegada` es ATiempo
Equivalencia de 1 en `EstadoLlegada` es Temprano
Equivalencia de 5 en `EstadoLlegada` es Desconocido
Equivalencia de -2,147,483,648 en `EstadoLlegada` es Desconocido
Equivalencia de 2,147,483,647 en `EstadoLlegada` es Desconocido

2.3 Los métodos ChangeType (Convert) y GetUnderlyingType (Enum)

En conjugación los métodos ChangeType [5] GetUnderlyingType [6] permiten obtener el valor asociado a un miembros de una enumeración. Esto puesto en práctica, obtenemos un ejemplo como el siguiente:

Tomemos como ejemplo la enumeración de la sección anterior:

internal enum EstadoLlegada
{
Desconocido = -3,
Retardado = -1,
ATiempo = 0,
Temprano = 1
}

En código cliente:

EstadoLlegada estado = EstadoLlegada.Temprano;
var numero = Convert.ChangeType(estado, Enum.GetUnderlying(typeof(EstadoLlegada)));
Console.WriteLine("Equivalencia de {0} en `EstadoLlegada` es {1}", numero, estado);

3. Transformación (parsing) de Valores de una Enumeración

En la clase Enum contamos con los siguientes métodos para hacer transformación (parsing, ~conversión) de cadenas de caracteres a valores de una enumeración:
  • Parse [7]: Convierte una cadena de caracteres (nombre de la constante/miembro) o valor numérico de la constante al objeto de la enumeración equivalente.
  • TryParse [8]: Ídem. Sin embargo, el valor devuelto indica si la conversión fue satisfactoria.
Estos dos métodos los podemos combinar con el método IsDefined para que una vez realizada la conversión validemos la existencia del elemento (constante) en la enumeración.

Verbigracia:


[Nota: Omito comentar el código. El archivo de código fuente incluye comentarios.]

Resultado:
Uso de los métodos Parse, TryParse de Enum
Figura 2. Uso de los métodos Parse, TryParse de Enum.

4. Formateo de Valores de una Enumeración

Los valores de una enumeración pueden ser convertidos a diferentes representaciones: hexadecimal (X o x), decimal (D o d), cadena de caracteres (F o f), y una representación alternativa entre una cadena de caracteres o el valor del miembro (G o g); estos valores bandera se pasan al método Enum.ToString [10] (más precisamente la versión sobrecargada ToString(string) [11]).

Para conocer más detalles de las cadenas de formateo ir a [9].

Recurramos a este código de ejemplo para comprender su utilidad:

string[] formatos = {"X", "D", "F", "G"};

EstadoLlegada estado = EstadoLlegada.Retardado;

foreach (string formato in formatos)
{
Console.WriteLine(estado.ToString(formato));
}

Resultado:

FFFFFFFF
-1
Retardado
Retardado

5. Iteración de Miembros de una Enumeración

Desde [2] nos instruyen que debido a que la clase Enum no implementa ninguna de las interfaces IEnumerable o IEnumerable<T> no podemos enumerar los miembros de la enumeración a través de un ciclo foreach.

La limitación anterior la podemos atacar a través de los dos mecanismos siguientes:

5.1 Uso del método GetNames

El método GetNames [12] recupera un arreglo de elementos string con los nombres de las constantes definidas en una enumeración. Veamos cómo funciona:

Archivo DemoGetNames.cs:

> Prueba de ejecución.

Resultado:

Miembros de `EstadoLlegada`.
 ATiempo (0)
 Desconocido (-3)
 Retardado (-1)
 Temprano (1)

5.2 Uso del método GetValues

El método GetValues [13] podemos recuperar un arreglo con los valores numéricos de las constantes (miembros) de una enumeración. Conozcamos más acerca de este método con este ejemplo:



Resultado:

Miembros de `EstadoLlegada`.
 ATiempo (0)
 Temprano (1)
 Desconocido (-3)
 Retardado (-1)

6. Conclusiones

Hemos aprendido acerca de las operaciones básicas de las enumeraciones. Primero vimos acerca de la conversión (con más detalle que la primera parte de esta serie de Enumeraciones en C#); más adelante: transformación (operación útil para convertir o hacer parsing de valores representados como cadenas); otra operación interesante, la de formateo, nos permite representar un valor de una constante en distintos formatos: decimal, cadena de caracteres, hexadecimal. Al final vimos cómo iterarar una enumeración a través de los métodos GetNames y GetValues.

7. Glosario

  • Conversión
  • Enum
  • Enumeración
  • Formateo
  • Iteración

8. 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 Class (System) - http://msdn.microsoft.com/en-us/library/system.enum%28v=vs.110%29.aspx
[3]: Enum.ToObject Method (System) - http://msdn.microsoft.com/en-us/library/System.Enum.ToObject%28v=vs.110%29.aspx
[4]: Enum.ToObject Method (Type, Int64) (System) - http://msdn.microsoft.com/en-us/library/dcz7khw0(v=vs.110).aspx
[5]: Convert.ChangeType Method (System) - http://msdn.microsoft.com/en-us/library/system.convert.changetype%28v=vs.110%29.aspx
[6]: Enum.GetUnderlyingType Method (System) - http://msdn.microsoft.com/en-us/library/system.enum.getunderlyingtype%28v=vs.110%29.aspx
[7]: Enum.Parse Method (System) - http://msdn.microsoft.com/en-us/library/system.enum.parse%28v=vs.110%29.aspx
[8]: Enum.TryParse Method (System) - http://msdn.microsoft.com/en-us/library/system.enum.tryparse%28v=vs.110%29.aspx
[9]: Enumeration Format Strings - http://msdn.microsoft.com/en-us/library/c3s1ez6e%28v=vs.110%29.aspx
[10]: Enum.ToString Method (System) - http://msdn.microsoft.com/en-us/library/system.enum.tostring%28v=vs.110%29.aspx
[11]: Enum.ToString Method (String) (System) - http://msdn.microsoft.com/en-us/library/a0h36syw%28v=vs.110%29.aspx
[12]: Enum.GetNames Method (System) - http://msdn.microsoft.com/en-us/library/system.enum.getnames%28v=vs.110%29.aspx
[13]: Enum.GetValues Method (System) - http://msdn.microsoft.com/en-us/library/system.enum.getvalues%28v=vs.110%29.aspx
[14]: Ideone.com - Online Compiler and IDE >> C/C++, Java, PHP, Python, Perl and 40+ other compilers and interpreters - http://ideone.com/


J

No hay comentarios:

Publicar un comentario

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