índice del curso de VB .NET

Curso de iniciación a la programación
con Visual Basic .NET

Entrega número siete, (06/Dic/2002)
Publicada el 06/Dic/2002


En esta entrega veremos otra forma con la que podemos escoger entre varias opciones. Hasta ahora hemos usado las instrucciones IF / Then / Else, pero Visual Basic pone a nuestra disposición la instrucción Select Case con la que podemos elegir entre varias opciones y en la versión .NET nos facilita un poco las cosas, al menos con respecto a como se usaba en las versiones anteriores de Visual Basic, esto lo comprobaremos en cuanto veamos una nueva forma de crear constantes.

Empecemos con la instrucción Select Case.
Esta instrucción se usa de la siguiente forma:
Select Case <expresión a evaluar>
Case <lista de expresiones>
  ' ...
Case <otra lista de expresiones>
  ' ...
Case Else
  ' si no se cumple ninguna de las listas de expresiones
End Select

Después de Select Case se pondrá una expresión a evaluar, es decir lo que queremos comprobar si se cumple o no, esto es lo mismo que hacemos con el If <expresión a evaluar> Then; lo que diferencia al Select Case del If... Then es que con el If... Then si queremos hacer varias comprobaciones, tendremos que usar diferentes If... Then con varios ElseIf..., mientras que con el Select Case, cada una de las cosas que queremos comprobar lo ponemos en los distintos Case... ¿cómo? ¿que no te enteras?, vale, veámoslo con un ejemplo.
Supongamos que queremos comprobar si el contenido de la variable i tiene distintos valores y según esos valores tendremos que hacer una cosa u otra.
Si lo hiciéramos usando If... Then, tendríamos que escribir algo como esto:

If i = 3 Then
    '
ElseIf i > 5 AndAlso i < 12 Then
    '
ElseIf i = 14 OrElse i = 17 Then
    '
ElseIf i > 25 Then
    '
Else
    '
End If

Esto mismo, con Select Case lo haríamos de esta forma:

Select Case i
    Case 3
        '
    Case 6 To 11
        '
    Case 14, 17
        '
    Case Is > 25
        '
    Case Else
        '
End Select

Como podemos comprobar, después de Select Case ponemos lo que queremos tener en cuenta, en este caso es el contenido de la variable i, cuando queremos comprobar si es igual a 3, simplemente ponemos el 3, lo mismo hacemos cuando queremos hacer algo para el caso de que el valor sea 14 o 17, pero en este caso simplemente especificamos los valores que queremos comprobar separados por comas, podemos poner tantos como necesitemos.
Si queremos comprobar un rango de valores, por ejemplo que el valor de i estuviera entre 5 y 12 (mayor que 5 y menor que 12), podemos hacerlo de esta forma: usamos 6 To 11, es decir queremos que esa condición se cumpla cuando el valor de i tenga un valor de 6 a 11.
Cuando queremos comprobar si el valor es mayor (o cualquier otra comprobación), usaremos Is, como en el caso de Is > 25, esto es lo mismo que comprobar si i es mayor que 25.
Por último, si ninguno de esos casos se cumple, se ejecutará lo que esté a continuación de Case Else, que funciona igual que el Else último que tenemos en el bloque If... Then.

Como vemos, funciona casi igual que con If... Then, pero de una forma algo más ordenada, la única pega es que sólo podemos evaluar una expresión, mientras que con If podemos usar tantas como queramos... precisamente por eso existen estas dos posibilidades... cuando una no es válida, podemos usar la otra.

Además de expresiones simples, en Select Case podemos indicar cualquier expresión válida, siempre que el resultado de esa expresión sea comparable con un valor, el cual, a su vez, producirá un valor verdadero o falso.
Estas expresiones, pueden ser tanto numéricas como de cadenas de caracteres.
No voy a dar ahora más ejemplos, ya que a lo largo de este curso de iniciación a la programación de Visual Basic .NET tendremos ocasión de ver más de un ejemplo del uso de Select Case (e incluso de If... Then), así que no te impacientes y si quieres ver ejemplos de Select Case, te invito a que le eches una ojeada a la documentación de Visual Studio .NET, que es bastante amplia y en algunos casos, hasta fácil de comprender... (bueno, sólo en algunos casos, ya que si siempre fuese tan "clara", ¿para que escribir nada que lo aclare...?)

Bien, sigamos nuestro aprendizaje, ahora vamos a ver esa otra forma de crear constantes que mencioné al principio.
Me estoy refiriendo a:

Las enumeraciones (Enum)

Como habrás podido ver en la descripción del glosario (si es que has seguido el link o enlace de la línea anterior), una enumeración es un tipo especial de variable numérica en la que los valores que dicha variable puede tomar, son constantes simbólicas, es decir que en lugar de usar un número, se usa una palabra (constante) que hace referencia a un número.
Por ejemplo, (si mejor pon un ejemplo, que si no, no hay quien te entienda), si queremos tener una variable llamada color la cual queremos que contenga un valor numérico que haga referencia a un color en particular, es que en lugar de usar el valor 1, 2 ó 3, queremos usar la constante rojo, azul, verde, etc. Esto lo haríamos de esta forma:

Enum colores
    rojo = 1
    azul
    verde
End Enum

Las declaraciones de las enumeraciones hay que hacerla fuera de cualquier procedimiento, por ejemplo dentro de una clase o un módulo, pero también pueden estar declarados dentro de un espacio de nombres, todo dependerá de la cobertura (o amplitud de acceso) que queramos darle. Además podemos poder darle las propiedades pública, privada, etc., como siempre, esto influirá en los sitios desde los que podemos usar esa enumeración.

Los valores que pueden tener los miembros de una enumeración, pueden ser cualquiera de los que un tipo numérico de tipo entero pueda tener. Por defecto el tipo es Integer, pero las enumeraciones también pueden ser de tipo Byte, Long o Short, para poder especificar un tipo diferente a Integer, lo indicaremos usando As Tipo después del nombre de la enumeración.
Por defecto, el primer valor que tendrá un elemento de una enumeración será cero y los siguientes elementos, salvo que se indique lo contrario, tendrán uno más que el anterior.
En el ejemplo mostrado, el elemento rojo, valdrá 1, azul valdrá 2 y verde tendrá un valor 3.
Para poder cambiar esos valores automáticos, podemos indicarlo usando una asignación como la usada para indicar que rojo vale 1: rojo = 1
En caso de que no indiquemos ningún valor, el primero será cero y los siguientes valdrán uno más que el anterior, por ejemplo, si la declaración anterior la hacemos de esta forma:

Enum colores
    rojo
    azul
    verde
End Enum

rojo valdrá 0, azul será igual a 1 y verde tendrá el valor 2.

La asignación podemos hacerla en cualquier momento, en el siguiente caso, rojo valdrá cero, azul tendrá el valor 3 y verde uno más que azul, es decir 4.

Enum colores
    rojo
    azul = 3
    verde
End Enum

Por supuesto, los valores que podemos asignar a los elementos (o miembros) de una enumeración serán valores que estén de acuerdo con el tipo de datos, recordemos que si no indicamos nada, serán de tipo Integer, pero si especificamos el tipo de datos, por ejemplo, de tipo Byte, el cual si recordamos la tabla vista en la cuarta entrega, sólo podrá contener valores enteros comprendidos entre 1 y 255. Sabiendo esto, no podríamos declarar la siguiente enumeración sin recibir un mensaje de error:

Enum colores As Byte
    azul = 255
    rojo
    verde
End Enum

¿Por qué? te preguntarás, ¿si el valor está dentro de los valores permitidos?
Por la sencilla razón de que azul tiene un valor adecuado, pero tanto rojo como verde, tendrán un valor 256 y 257 respectivamente, los cuales están fuera del rango permitido por el tipo Byte.


Figura 1. Los valores de los miembros de las enumeraciones
deben estar comprendidos en el rango del tipo usado.

Otra cosa con la que tendremos que andarnos con cuidado al usar las enumeraciones, es que una variable declarada del tipo de una enumeración, en teoría no debería admitir ningún valor que no esté incluido en dicha enumeración, aunque esta restricción es sólo "recomendable", no es algo "obligatorio", aunque si tenemos activado Option Strict On, el IDE de Visual Studio .NET nos lo recordará, con lo cual nos obligará a hacer una conversión de datos entre la variable (o el valor usado) y el tipo "correcto" al que corresponde la enumeración.
Para entenderlo mejor, veamos un ejemplo:

Dim unColor As colores
'
unColor = 1

Aunque el valor 1, sea un valor correcto, si tenemos Option Strict On, nos indicaría que no se permite la conversión implícita entre Integer y el tipo colores. Si no tuviéramos activada la comprobación estricta, (cosa que yo te recomiendo y si pudiera, hasta te obligaría a usar, más que nada porque así aprenderás a hacer las cosas bien, que siempre habrá tiempo de hacerlas mal), a lo que iba, si no tuvieras esa opción activada, no te mostraría ningún error, pero si sabemos que para un buen uso de los tipos de datos, deberíamos hacer la conversión correspondiente, ¿por qué no hacerla?
Si te portas como el Guille quiere, tendrías que hacer lo siguiente:

unColor = CType(1, colores)

Es decir, usamos CType para hacer la conversión entre el número y el tipo correcto de datos.

De todas formas, te diré que si usas el IDE de Visual Studio .NET, éste te mostrará los valores que puedes asignarle a la variable declarada del tipo colores:


Figura 2. Las variables del tipo de una enumeración sólo
deberían tener los valores de dicha enumeración

Al igual que ocurre con las variables de tipo Boolean, (que sólo pueden tomar los valores True o False), cuando vamos a asignar un valor, se nos muestra los valores posibles, esto mismo también ocurre si queremos usar esa variable en en una comparación o en un Select Case, a esto es a lo que me refería al principio de esta entrega.
Veamos lo que nos mostraría el IDE al usar la variable unColor en los casos antes mencionados:


Una enumeración en una comparación If


Una variable enumerada en un Select Case

 

En las versiones anteriores de Visual Basic, podíamos usar los miembros de las enumeraciones sin indicar la enumeración a la que pertenecen, por ejemplo, podíamos asignar el valor azul a una variable del tipo colores, pero en Visual Basic .NET esto ya no es posible, si queremos usar el miembro azul, tenemos que indicar la enumeración a la que pertenece, por ejemplo con unColor = colores.azul, esto más que un inconveniente es una ventaja, ya que así no habrá posibilidades de "mal interpretación" o mal uso de los miembros de una enumeración.

Como he mencionado antes, deberíamos hacer la comprobación correspondiente para saber si el valor que estamos asignando a una variable "enumerada" es el adecuado o no, por ejemplo, si el parámetro de un procedimiento recibe un tipo enumerado, puede ser que el valor con el que se llame a ese procedimiento no sea un valor válido, ¿cómo podemos evitar estos casos?
En principio podríamos hacer una comprobación, bien usando comparaciones If o, mejor aún, usando Select Case, para el caso de la enumeración colores no habría mucho problema, ya que sólo tiene tres valores y esa comprobación podría quedar de esta forma:

Private Sub pruebaColores(ByVal elColor As colores)
    Select Case elColor
        Case colores.azul, colores.rojo, colores.verde
            ' OK
        Case Else
            ' si no es ninguno de los válidos,
            ' asignamos uno por defecto
            elColor = colores.azul
    End Select
    ' resto del código...
End Sub

Esto está bien, ya que, a pesar de que usemos CType para convertir un valor en la enumeración, no evita que que se "cuele" un valor erróneo:

pruebaColores(CType(12, colores))

Esta llamada sería correcta, pero el valor no estaría dentro de los valores válidos, aunque no produciría ningún tipo de error, ya que, aunque 12 no sea un valor válido del tipo colores, si que es un valor válido del tipo Integer, que al fin y al cabo es el tipo de valores que admiten las variables declaradas como colores.
En el procedimiento, se comprueba si el valor pasado en el parámetro es del tipo adecuado y se actuaría de la forma que nosotros quisiéramos. El problema vendría si la cantidad de miembros de la enumeración fuese muy extensa y esos valores no fuesen consecutivos, ya que nos obligaría a hacer muchas "comparaciones" para poder saber si el valor indicado es uno de los valores correctos.
Para poder solventar este "problemilla", tendremos que echar mano del propio .NET Framework, en particular de la clase Enum, esta clase tiene una serie de métodos "estáticos" que podemos usar para distintas circunstancias, en nuestro caso particular, podemos usar el método IsDefined que devolverá un valor verdadero o falso, según el valor indicado esté o no definido en la enumeración.

Por ejemplo si hacemos esto:
If System.Enum.IsDefined(unColor.GetType, 12) Then
o esto otro, que para el caso es lo mismo, ya que el primer parámetro de esta función espera un tipo:
If System.Enum.IsDefined(GetType(colores), 12) Then
Se devolverá un valor falso, ya que 12 no es miembro de la enumeración colores.
En el primer caso usamos la variable del tipo colores (unColor) y usamos el método GetType para saber que tipo de datos es esa variable y en el segundo ejemplo, usamos la función GetType para averiguar el tipo del parámetro indicado.
Veamos el código del procedimiento pruebaColores usando este nuevo sistema de averiguar si un valor es o no correcto (o válido) para la enumeración indicada.

Private Sub pruebaColores(ByVal elColor As colores)
    If System.Enum.IsDefined(elColor.GetType, elColor) = False Then
        elColor = colores.azul
        Console.WriteLine("el valor no es correcto")
    Else
        Console.WriteLine("valor correcto")
    End If
    ' resto del código...
End Sub

Aunque no debes preocuparte demasiado, al menos por ahora, si no llegas a entender todo esto que estamos viendo, simplemente "acepta" que funciona y más adelante te das una vueltecita por esta entrega y seguro que lo comprenderás mejor. De todas formas, te voy a explicar con más o menos detalle que es lo que se hace en este procedimiento.
La función IsDefined espera dos parámetros, el primero es el tipo de una enumeración, todos los objetos de .NET Framework tienen el método GetType que indica ese tipo de datos, en este caso usamos la variable elColor (que es del tipo colores) y mediante el método GetType, indicamos el dato que esa función espera. En el segundo parámetro, hay que indicar un valor que será el que se compruebe si está o no definido en dicha enumeración, si ese valor es uno de los incluidos en la enumeración indicada por GetType, la función devolverá True, en caso de que no sea así, devolverá un valor False.

Además de IsDefined, la clase Enum tiene otros métodos que pueden sernos útiles. Pero en lugar de enumerártelos aquí, dejaré que le eches un vistazo a la documentación del .NET Framework (o de Visual Studio .NET), para que practiques en el uso de dicha documentación...
(Guille, no seas malo, anda, dale aunque sea un par de ejemplos, bueno, pero es que si no, no leen la documentación y así... pues no aprenden...)
Valeee, está bien, veamos algunos de los métodos de la clase Enum: (que hay que usar con el System. delante para que el VB no se confunda con el "intento" de una declaración del tipo Enum)

GetName, indica el nombre con el que se ha declarado el miembro de la enumeración, por ejemplo, en el ejemplo de la enumeración colores mostrada en la figura 2, el valor 1, sería azul:
System.Enum.GetName(unColor.GetType, 1)
En caso de que el valor indicado no pertenezca a la enumeración, devolverá una cadena vacía.
También se pude obtener el "nombre" del miembro usando ToString: unColor.ToString

GetNames, devuelve un array de tipo String con los nombres de todos los miembros de la enumeración.
Lo que es un array lo veremos en detalle en otra ocasión, pero espero que puedas comprender qué es lo que hace el siguiente código sin que te de un "dolor" de cabeza.

Dim a() As String = System.Enum.GetNames(unColor.GetType)
Dim i As Integer
For i = 0 To a.Length - 1
    Console.WriteLine("el valor {0} es {1}", i, a(i))
Next

GetValues, devuelve un array con los valores de los miembros de la enumeración.
El tipo devuelto es del tipo Array, que en realidad no es un array (o matriz) de un tipo de datos específico, sino más bien es el tipo de datos en el que se basan los arrays o matrices.

Dim a As Array = System.Enum.GetValues(unColor.GetType)
For i = 0 To a.Length - 1
    Console.WriteLine("el valor {0} es {1}", i, a.GetValue(i))
Next

Por último vamos a ver un método que, casi con toda seguridad veremos en más de una ocasión:
Parse, devuelve un valor de tipo Object con el valor de la representación de la cadena indicada en el segundo parámetro. Esa cadena puede ser un valor numérico o una cadena que representa a un miembro de la enumeración.

System.Enum.Parse(unColor.GetType, "1")
System.Enum.Parse(unColor.GetType, "azul")

Hay más métodos, pero creo que estos que acabo de enumerar son los más interesantes, de todas formas, te invito a seguir investigando por tu cuenta... cosa que, aunque yo no te lo dijera, deberías acostumbrarte a hacer.

Pero ya que estamos con esto de Parse y para ir terminando esta entrega, veamos cómo podemos usar ese método para los tipos de datos que podemos usar en .NET Framework (los cuales vimos en la cuarta entrega).
El método Parse se utiliza para convertir una cadena en un valor numérico, el tipo de número devuelto dependerá del tipo desde el que hemos usado ese método, por ejemplo si hacemos lo siguiente:

Dim s As String = "123"
Dim i As Integer = Integer.Parse(s)

El valor asignado a la variable numérica i, sería el valor 123 que es un número entero válido.
Pero si hacemos esto otro:

Dim b As Byte = Byte.Parse(s)

También se asignaría el valor 123 a la variable b, que es de tipo Byte, pero el número 123 ya no es un número entero, sino del tipo byte... esto es claro, dirás, pero, si el valor guardado en la variable s no estuviese dentro del "rango" de valores aceptados por el tipo Byte, esto produciría una excepción (o error).

s = "129.33"
i = Integer.Parse(s)

En este caso, el error se produce porque 129.33 no es un número entero válido, por tanto, cuando usemos Parse, o cualquiera de las funciones de conversión, tendremos que tener cuidado de que el valor sea el correcto para el tipo al que queramos asignar el valor...

¿Cómo solucionar este pequeño inconveniente?
No perdiéndote la próxima entrega de este Curso de Iniciación a la Programación con Visual Basic .NET, ya que esta entrega se acaba aquí, así que... a esperar... ¡que remedio!
Pero no te preocupes que no tendrás que esperar mucho... (al menos intentaré que sea antes de que acabe este "pedazo" de puente de la Constitución que empezó hoy día 6 y que dura hasta el lunes día 9)

Veamos las cosillas que hemos visto en esta séptima entrega:
Hemos visto cómo elegir entre varias opciones mediante Select Case, también sabemos cómo crear enumeraciones o constantes simbólicas que están relacionadas de alguna forma, también hemos visto algunos métodos de la clase Enum con los que podemos saber si un valor pertenece a los definidos en la enumeración o con los que podemos saber los nombres de los miembros de dicha enumeración, además de saber cómo podemos convertir cadenas de caracteres en un valor numérico, mediante el método Parse.

Para la próxima entrega veremos cómo detectar o interceptar errores y algunas otras cosillas, como el tema que también hemos tratado, aunque sólo haya sido de pasada, sobre los arrays o matrices.


Nos vemos.
Guillermo
Nerja, 06 de Diciembre de 2002


ir a la entrega anterior ir al índice del curso vb.NET
 
ir al Glosario .NET
ir a la siguiente entrega (o al índice si esta es la última)

la Luna del Guille o... el Guille que está en la Luna... tanto monta...