El nombre de los miembros de las enumeraciones
Tanto si indicamos o no el atributo Flags a una enumeración, la podemos usar de
esta forma:
Dim c As Colores =
Colores.Azul Or Colores.Rojo
Es decir, podemos "sumar" los valores definidos en la
enumeración. Antes de
explicar con detalle que beneficios nos puede traer el uso de este
atributo, veamos
una característica de las enumeraciones.
Como hemos comentado, las enumeraciones son constantes con nombres,
pero en
Visual Basic 2008 esta definición llega más lejos, de hecho,
podemos saber "el
nombre" de un valor de una enumeración, para ello tendremos
que usar el método
ToString, (el cual se usa para convertir en
una cadena cualquier valor numérico).
Por ejemplo, si tenemos la siguiente asignación:
Dim s As String = Colores.Azul.ToString
La variable s contendrá la palabra "Azul" no
el valor 4.
Esto es aplicable a cualquier tipo de enumeración, se haya o no
usado el atributo
FlagsAttribute.
Una vez aclarado este comportamiento de las enumeraciones en
Visual Basic
2008, veamos que es lo que ocurre cuando sumamos valores de
enumeraciones a
las que hemos aplicado el atributo Flags y a las que no se lo hemos aplicado.
Empecemos por este último caso.
Si tenemos este código:
Enum Colores As Byte
Rojo = 1
Verde = 2
Azul = 4
End Enum
Dim c As Colores = Colores.Azul Or Colores.Rojo
Dim s As String = c.ToString
El contenido de la variable s
será "5", es decir, la
representación numérica del
valor contenido: 4
+ 1, ya que el valor de la constante Azul es 4 y el de la
constante Rojo es 1.
Pero si ese mismo código lo usamos de esta forma (aplicando el
atributo Flags a la
enumeración):
<Flags()>
_
Enum Colores As Byte
Rojo = 1
Verde = 2
Azul = 4
End Enum
Dim c As Colores = Colores.Azul Or Colores.Rojo
Dim s As String = c.ToString
El contenido de la variable s
será: "Rojo, Azul",
es decir, se asignan los nombres
de los miembros de la enumeración que intervienen en ese valor, no
el valor
"interno".
Los valores de una enumeración no son simples números
Como hemos comentado, los miembros de las enumeraciones realmente
son
valores de un tipo de datos entero (en cualquiera de sus
variedades) tal como
podemos comprobar en la figura 2.7:
Figura 2.7. Los tipos subyacentes posibles de una enumeración
Por tanto, podemos pensar que podemos usar cualquier valor para
asignar a una
variable declarada como una enumeración, al menos si ese valor
está dentro del
rango adecuado.
En Visual Basic 2008 esto no es posible, al menos si lo hacemos de
forma "directa"
y con Option Strict conectado, ya que recibiremos un error indicándonos que no
podemos convertir, por ejemplo, un valor entero en un valor del
tipo de la
enumeración. En la figura 2.8 podemos ver ese error al intentar
asignar el valor 3
a una variable del tipo Colores
(definida con el tipo predeterminado Integer).
Figura 2.8. Error al asignar un valor "normal" a una
variable del tipo
Colores
El error nos indica que no podemos realizar esa asignación, pero
el entorno
integrado de Visual Studio 2008 también nos ofrece alternativas
para que ese
error no se produzca, esa ayuda se obtiene presionando en el signo
de admiración
que tenemos justo donde está el cursor del mouse, pero no s olo
nos dice cómo
corregirlo, sino que también nos da la posibilidad de que el
propio IDE se encargue
de corregirlo, tal como podemos apreciar en la figura 2.9.
Figura 2.9. Opciones de corrección de errores
Lo único que tendríamos que hacer es presionar en la sugerencia de
corrección,
que en este caso es la única que hay, pero en otros casos pueden
ser varias las
opciones y tendríamos que elegir la que creamos adecuada.
El código final (una vez corregido) quedaría de la siguiente forma:
Dim c As Colores = CType(3, Colores)
CType es una de las formas que nos ofrece
Visual Basic 2008 de hacer
conversiones entre diferentes tipos de datos, en este caso
convertimos un valor
entero en uno del tipo Colores.
Si compilamos y ejecutamos la aplicación, ésta funcionará
correctamente.
Aunque sabemos que es posible que usando CType no asignemos un valor dentro
del rango permitido. En este caso, el valor 3 podríamos darlo por
bueno, ya que es
la suma de 1 y 2 (Rojo
y Verde), pero ¿que pasaría si el valor
asignado es, por
ejemplo, 15? En teoría no deberíamos permitirlo.
Estas validaciones podemos hacerlas de dos formas:
1- Con la clásica solución de comprobar el valor indicado con
todos los valores
posibles.
2- Usando funciones específicas del tipo Enum. Aunque en este último caso, solo
podremos comprobar los valores definidos en la enumeración.
En el siguiente ejemplo podemos hacer esa comprobación.
Sub mostrarColor(ByVal c As Colores)
'
comprobar si el valor indicado es correcto
' si no
está¡ definido, usar el valor Azul
If [Enum].IsDefined(GetType(Colores), c) = False Then
c = Colores.Azul
End If
Console.WriteLine("El color es
{0}", c)
End Sub
Este código lo que hace es comprobar si el tipo de datos Colores tiene definido el
valor contenido en la variable c, en caso de que no sea así, usamos
un valor
predeterminado.
Nota:
La función IsDefined
sólo comprueba los valores que se han
definido
en la enumeración, no las posibles combinaciones que podemos
conseguir sumando cada uno de sus miembros, incluso aunque
hayamos usado el atributo FlagsAttribute.
Ver vídeo 1 de esta lección (Enumeraciones
1) - video en Visual
Studio 2005 válido para Visual Studio 2008
Ver vídeo 2 de esta lección (Enumeraciones
2) - video en Visual
Studio 2005 válido para Visual Studio 2008
Ver vídeo 3 de esta lección (Enumeraciones
3) - video en Visual
Studio 2005 válido para Visual Studio 2008
Ver vídeo 4 de esta lección (Enumeraciones
4) - video en Visual
Studio 2005 válido para Visual Studio 2008
Arrays
(matrices)
Los arrays (o matrices) nos permitirán agrupar valores que de
alguna forma
queremos que estén relacionados entre si.
Nota:
Esta es la definición usada en la documentación de Visual Studio
sobre qué es una matriz:
"Una matriz es una estructura de datos que contiene una serie
de
variables denominadas elementos de la matriz."
Aclaramos este punto, porque la traducción en castellano de Array
puede variar dependiendo del país, pero aquí utilizaremos la usada
a
lo largo de la documentación de Visual Studio.
Declarar arrays
En C# los arrays se definen indicando un par de corchetes en el
tipo de datos.
En Visual Basic 2008 la declaración de un array la haremos usando
un par de
paréntesis en el nombre de la variable o del tipo, en el siguiente
ejemplo
declaramos un array de tipo String llamado nombres:
Dim nombres() As String
Dim nombres As String()
Estas dos formas son equivalentes.
También podemos indicar el número de elementos que contendrá el
array:
Dim nombres(10) As String
Pero solo podemos hacerlo en el nombre, si esa cantidad de
elementos lo
indicamos en el tipo, recibiremos un error indicándonos que "los límites de la
matriz no pueden aparecer en los especificadores del tipo".
Al declarar un array indicando el número de elementos, como es el
caso anterior,
lo que estamos definiendo es un array de 11 elementos: desde cero
hasta 10, ya
que en Visual Basic 2008, al igual que en el resto de lenguajes de
.NET, todos los
arrays deben tener como índice inferior el valor cero.
Para que quede claro que el límite inferior debe ser cero, en
Visual Basic 2008
podemos usar la instrucción 0 To para indicar el valor máximo del
índice superior,
ya que, tal como podemos comprobar si vemos 0 To 10, quedará claro
que
nuestra intención es declarar un array con 11 elementos, o al
menos nue stro
código resultará más legible:
Dim nombres(0 To 10) As String
Declarar e inicializar un array
En Visual Basic 2008 también podemos inicializar un array al
declararlo, para ello
debemos poner los valores a asignar dentro de un para de llaves,
tal como v emos
en el siguiente ejemplo:
Dim nombres() As String = {"Pepe", "Juan", "Luisa"}
Con el código anterior estamos creando un array de tipo String con tres valores
cuyos índices van de cero a dos.
En este caso, cuando iniciamos el array al declararlo, no deb emos
indicar el
número de elementos que tendrá ese array, ya que ese valor lo
averiguará el
compilador cuando haga la asignación. Tampoco es válido indicar el
número de
elementos que queremos que tenga y solo asignarle unos cuantos
menos (o más),
ya que se producirá un error en tiempo de compilación.
Si el array es bidimensional (o con más dimensiones), también
podemos
inicializarlos al declararlo, pero en este caso debemos usar doble
juego de llaves:
Dim nombres(,) As String = {{"Juan", "Pepe"}, {"Ana",
"Eva"}}
En este código tendríamos un array bidimensional con los
siguientes valores:
nombres(0,0)= Juan
nombres(0,1)= Pepe
nombres(1,0)= Ana
nombres(1,1)= Eva
Como podemos ver en la declaración anterior, si definimos arrays
con más de una
dimensión, debemos indicarlas usando una coma para separar cada
dimensión, o
lo que es más fácil de recordar: usando una coma menos del número
de
dimensiones que tendrá el array. En los valores a asignar,
usaremos las llaves
encerradas en otras llaves, según el número de dimensiones.
Aunque, la verdad, es que hay algunas veces hay que hacer un gran
esfuerzo
mental para asociar los elementos con los índices que tendrán en
el array, por
tanto, algunas veces puede que resulte más legible si indentamos o
agrupamos
esas asignaciones, tal como vemos en el siguiente código:
Dim nomTri(,,) As String = _
{ _
{{"Juan", "Pepe"}, {"Luisa", "Eva"}}, _
{{"A", "B"}, {"C", "D"}} _
}
Console.WriteLine(nomTri(0,
0, 0)) ' Juan
Console.WriteLine(nomTri(0,
0, 1)) ' Pepe
Console.WriteLine(nomTri(0,
1, 0)) ' Luisa
Console.WriteLine(nomTri(0,
1, 1)) ' Eva
Console.WriteLine(nomTri(1,
0, 0)) ' A
Console.WriteLine(nomTri(1,
0, 1)) ' B
Console.WriteLine(nomTri(1,
1, 0)) ' C
Console.WriteLine(nomTri(1,
1, 1)) ' D
Tal como podemos comprobar, asi es más legible. Por suerte tenemos
el carácter
del guión bajo para continuar líneas de código.
Cambiar el tamaño de un array
Para cambiar el tamaño de un array, usaremos la instrucción ReDim, esta
instrucción solo la podemos usar para cambiar el tamaño de un
array previamente
declarado, no para declarar un array, ya que siempre hay que
declarar
previamente los arrays antes de cambiarles el tamaño.
Dim nombres() As String
...
ReDim nombres(3)
nombres(0)
= "Juan"
nombres(1)
= "Pepe"
La mayor utilidad de esta instrucción, es que podemos cambiar el
tamaño de un
array y mantener los valores que tuviera anteriormente, para
lograrlo debemos
usar ReDim Preserve.
ReDim
Preserve nombres(3)
nombres(2)
= "Ana"
nombres(3)
= "Eva"
En este ejemplo, los valores que ya tuviera el array nombres, se seguirían
manteniendo, y se asignarían los nuevos.
Si bien tanto ReDim como ReDim
Preserve se pueden usar en arrays de cualquier
número de dimensiones, en los arrays de más de una dimensión
solamente
podemos cambiar el tamaño de la última dimensión.
Eliminar el contenido de un array
Una vez que hemos declarado un array y le hemos asignado valores,
es posible
que nos interese eliminar esos valores de la memoria, para
lograrlo, podemos
hacerlo de tres formas:
1. Redimensionando el array indicando que tiene cero elementos,
aunque en el
mejor de los casos, si no estamos trabajando con arrays de más de
una
dimensión, tendríamos un array de un elemento, ya que, como hemos
comentado anteriormente, los arrays de .NET el índice inferior es
cero.
2. Usar la instrucción Erase. La instrucción Erase elimina totalmente el array de
la memoria.
3. Asignar un valor Nothing al array. Esto funciona en Visual
Basic 2008 porque
los arrays realmente son tipos por referencia.
Los arrays son tipos por referencia
Como acabamos de ver, en Visual Basic 2008 los arrays son tipos
por referencia, y
tal como comentamos anteriormente, los tipos por referencia
realmente lo que
contienen son una referencia a los datos reales no los datos
propiame nte dichos.
¿Cual es el problema?
Veámoslo con un ejemplo y así lo tendremos más claro.
Dim nombres() As String = {"Juan", "Pepe", "Ana",
"Eva"}
Dim otros() As String
otros =
nombres
nombres(0)
= "Antonio"
En este ejemplo definimos el array nombres y le asignamos cuatro valores. A
continuación definimos otro array llamado otros y le asignamos lo que tiene
nombres. Por último asignamos un nuevo valor
al elemento cero del array
nombres.
Si mostramos el contenido de ambos arrays nos daremos cuenta de
que realmente
solo existe una copia de los datos en la memoria, y tanto nombres(0) como
otros(0) contienen el nombre "Antonio".
¿Qué ha ocurrido?
Que debido a que los arrays son tipos por referencia, solamente
existe una copia
de los datos y tanto la variable nombres como la variable otros lo
que contienen es
una referencia (o puntero) a los datos.
Si realmente queremos tener copias independientes, debemos hacer
una copia del
array nombres en el array otros, esto es fácil de hacer si usamos
el método
CopyTo. Éste método existe en todos los
arrays y nos permite copiar un array en
otro empezando por el índice que indiquemos.
El único requisito es que el array de destino debe estar
inicializado y tener espacio
suficiente para contener los elementos que queremos copiar.
En el siguiente código de ejemplo hacemos una copia del contenido
del array
nombres en el array otros, de esta forma, el cambio realizado
en el elemento
cero de nombres no afecta al del array otros.
Dim nombres() As String = {"Juan", "Pepe", "Ana", "Eva"}
Dim otros() As String
ReDim otros(nombres.Length)
nombres.CopyTo(otros,
0)
nombres(0)
= "Antonio"
Además del método CopyTo, los arrays tienen otros miembros
que nos pueden ser
de utilidad, como por ejemplo la propiedad Length usada en el ejemplo para saber
cuantos elementos tiene el array nombres.
Para averiguar el número de elementos de un array, (realmente el
índice
superior), podemos usar la función UBound.
También podemos usar la función LBound, (que sirve para averiguar el índice
inferior de un array), aunque no tiene ningún sentido en Visual
Basic 2008, ya
que, como hemos comentado, todos los arrays siempre tienen un
valor cero como
índice inferior.
Para finalizar este tema, solo nos queda por decir, que los arrays
de Visual Basic
2008 realmente son tipos de datos derivados de la clase Array y por tanto
disponen de todos los miembros definidos en esa clase, aunque de
esto
hablaremos en la próxima lección, en la que también tendremos la
oportunidad de
profundizar un poco más en los tipos por referencia y en como
podemos definir
nuestros propios tipos de datos, tanto por referencia como por
valor.
Ver vídeo 1 de esta lección (Arrays
Parte 1) - video en Visual Studio
2005 válido para Visual Studio 2008
Ver vídeo 2 de esta lección (Arrays
Parte 2) - video en Visual Studio
2005 válido para Visual Studio 2008
Ver vídeo 3 de esta lección (Arrays
Parte 3) - video en Visual Studio
2005 válido para Visual Studio 2008
Introducción
En la lección anterior vimos los tipos de datos predefinidos en .NET
Framework, en
esta lección veremos cómo podemos crear nuestros propios tipos de
datos, tanto
por valor como por referencia.
También tendremos ocasión de ver los distintos niveles de
accesibilidad que
podemos aplicar a los tipos, así como a los distintos miembros d e
esos tipos de
datos. De los distintos miembros que podemos definir en nuestros
tipos, nos
centraremos en las propiedades para ver en detalle los cambios que
han sufrido
con respecto a VB6. También veremos temas relacionados con la
programación
orientada a objetos (POO) en general y de forma particular los que
atañen a las
interfaces.
Clases y estructuras
· Clases:
Tipos por referencia definidos por el usuario
o Las clases: El corazón de .NET Framework
o La herencia: Característica principal de la Programación
Orientada a
Objetos
o Encapsulación y Polimorfismo
o Object: La clase base de todas las clases de .NET
· Definir
una clase
o Una clase especial: Module
o Los miembros de una clase
o Características de los métodos y propiedades
§ Accesibilidad, ámbito y miembros compartidos
§ Parámetros y parámetros opcionales
§ Array de parámetros opcionales (ParamArray)
§ Sobrecarga de métodos y propiedades
§ Parámetros por valor y parámetros por referencia
· Instanciar:
Crear un objeto en la memoria
o Declarar primero la variable y después instanciarla
o Declarar y asignar en un solo paso
o El constructor: El punto de inicio de una clase
o Constructores parametrizados
o Cuando Visual Basic 2008 no crea un constructor
automáticamente
o El destructor: El punto final de la vida de una clase
o Inicialización directa de objetos
· Estructuras:
Tipos por valor definidos por el usuario
o Definir una estructura
o Constructores de las estructuras
o Destructores de las estructuras
o Los miembros de una estructura
o Cómo usar las estructuras
· Accesibilidad
y ámbito
o Ámbito
§ Ámbito de bloque
§ Ámbito de procedimiento
§ Ámbito de módulo
§ Ámbito de espacio de nombres
o La palabra clave Global
o Accesibilidad
§ Accesibilidad de las variables en los procedimientos
o Las accesibilidades predeterminadas
o Anidación de tipos
§ Los tipos anidables
§ El nombre completo de un tipo
§ Importación de espacios de nombres
§ Alias de espacios de nombres
· Propiedades
o Definir una propiedad
o Propiedades de solo lectura
o Propiedades de solo escritura
o Diferente accesibilidad para los bloques Get y Set
o Propiedades predeterminadas
§ Sobrecarga de propiedades predeterminadas
· Interfaces
o ¿Qué es una interfaz?
o ¿Qué contiene una interfaz?
o Una interfaz es un contrato
o Las interfaces y el polimorfismo
o Usar una interfaz en una clase
o Acceder a los miembros implementados
o Saber si un objeto implementa una interfaz
o Implementación de múltiples interfaces
o Múltiple implementación de un mismo miembro
o ¿Dónde podemos implementar las interfaces?
o Un ejemplo práctico usando una interfaz de .NET
Clases:
Tipos por referencia definidos por el usuario
Tal como vimos en la lección anterior, los tipos de datos se
dividen en dos grupos:
tipos por valor y tipos por referencia. Los tipos por referencia
realmente son
clases, de la cuales debemos crear una instancia para poder
usarlas, esa instancia
o copia, se crea siempre en la memoria lejana (heap) y las variables lo único que
contienen es una referencia a la dirección de memoria en l a que
el CLR (Common
Language Runtime,
motor en tiempo de ejecución de .NET), ha almacenado el
objeto recién creado.
En .NET Framework todo es de una forma u otra una clase, por tanto
Visual Basic
2008 también depende de la creación de clases para su funci
onamiento, ya que
todo el código que escribamos debemos hacerlo dentro de una clase.
Antes de entrar en detalles sintácticos, veamos la importancia que
tienen las
clases en .NET Framework y como repercuten en las que podamos
definir nosotros
usando Visual Basic 2008.
Las clases: el corazón de .NET Framework
Prácticamente todo lo que podemos hacer en .NET Framework lo
hacemos
mediante clases. La librería de clases de .NET Framework es
precisamente el
corazón del propio .NET, en esa librería de clases está to do lo
que podemos hacer
dentro de este marco de programación; para prácticamente cualquier
tarea que
queramos realizar existen clases, y si no existen, las podemos
definir nosotros
mismos, bien ampliando la funcionalidad de alguna clase existente mediante
la
herencia, bien implementando algún tipo de funcionalidad
previamente definida o
simplemente creándolas desde cero.
La
herencia: Característica principal de la Programación Orientada a
Objetos
El concepto de Programación Orientada a Objetos (POO) es algo
intrínsico al
propio .NET Framework, por tanto es una característica que todos
los lenguajes
basados en este "marco de trabajo" tienen de forma
predeterminada, entre ellos el
Visual Basic 2008. De las características principales de la POO
tenemos que
destacar la herencia, que en breve podemos definir como una
característica que
nos permite ampliar la funcionalidad de una clase existente sin
perder la que ya
tuviera previamente. Gracias a la herencia, podemos crear una
nueva clase que se
derive de otra, esta nueva clase puede cambiar el comportamiento
de la clase
base y/o ampliarlo, de esta forma podemos adaptar la clase,
llamémosla, original
para adaptarla a nuestras necesidades.
El tipo de herencia que .NET Framework soporta es la herencia simple,
es decir ,
solo podemos usar una clase como base de la nueva, si bien, como
veremos más
adelante, podemos agregar múltiple funcionalidad a nuestra nueva
clase. Esta
funcionalidad nos servirá para aprovechar la funcionalidad de
muchas de las clases
existentes en .NET Framework, funcionalidad que solamente podremos
aplicar si
previamente hemos firmado un contrato que asegure a la clase de
.NET que la
nuestra está preparada para soportar esa funcionalidad, esto lo
veremos dentro de
poco con más detalle.
Encapsulación
y Polimorfismo
La encapsulación y el polimorfismo son otras dos características
de la
programación orientada a objetos.
La encapsulación nos permite abstraer la forma que tiene de actuar
una clase
sobre los datos que contiene o manipula, para poder lograrlo se
exponen como
parte de la clase los métodos y propiedades necesarios para que
podamos manejar
esos datos sin tener que preocuparnos cómo se realiza dicha
manipulación.
El polimorfismo es una característica que nos permite realizar
ciertas acciones o
acceder a la información de los datos contenidos en una clase de
forma semi -
anónima, al menos en el sentido de que no tenemos porqué saber
sobre que tipo
objeto realizamos la acción, ya que lo único que nos debe
preocupar es que
podemos hacerlo, por la sencilla razón de que estamos usando
ciertos mecanismos
que siguen unas normas que están adoptadas por la clase.
El ejemplo clásico del polimorfismo es que si tengo un objeto que
"sabe" cómo
morder, da igual que lo aplique a un ratón o a un dinosaurio,
siempre y cuando
esas dos "clases" expongan un método que pueda realizar
esa acción... y como
decía la documentación de Visual Basic 5.0, siempre será
preferible que nos
muerda un ratón antes que un dinosaurio.
Object:
La clase base de todas las clases de .NET
Todas las clases de .NET se derivan de la clase Object, es decir, lo indiquemos o
no, cualquier clase que definamos tendrá el comportamiento
heredado de esa
clase. El uso de la clase Object como base del resto de las clases de
.NET es la
única excepción a la herencia simple soportada por .NET, ya que de
forma
implícita, todas las clases de .NET se derivan de la clase Object
independientemente de que estén derivadas de cualquier otra.
Esta característica nos asegura que siempre podremos usar un
objeto del tipo
Object para acceder a cualquier clase de
.NET, aunque no debemos abrumarnos
todavía, ya que en el texto que sigue veremos con más detalle que
significado
tiene esta afirmación.
De los miembros que tiene la clase Object debemos resaltar el método ToString, el
cual ya lo vimos en la lección anterior cuando queríamos convertir
un tipo
primitivo en una cadena. Este método está pensado para devolver
una
representación en formato cadena de un objeto. El valor que
obtengamos al usar
este método dependerá de cómo esté definido en cada clase y por
defecto lo que
devuelve es el nombre completo de la clase, si bien en la mayoría
de los casos el
valor que obtendremos al usar este método debería ser más
intuitivo, por ejemplo
los tipos de datos primitivos tienen definido este método para
devuelva el valor
que contienen, de igual forma, nuestras clases también deberían
devolver un valor
adecuado al contenido almacenado. De cómo hacerlo, nos ocuparemos
en breve.
Nota:
Todos los tipos de datos de .NET, ya sean por valor o por
referencia
siempre están derivados de la clase Object, por tanto podremos
llamar a cualquiera de los métodos que están definidos en esa
clase.
Aunque en el caso de los tipos de datos por valor, cuando queremos
acceder a la clase Object que contienen, .NET Framework primero
debe convertirla en un objeto por referencia (boxing) y cuando
hemos dejado de usarla y queremos volver a asignar el dato a la
variable por valor, tiene que volver a hacer la conversión inversa
(unboxing).
Ver vídeo de esta lección (Clases
1) - video en Visual Studio 2005
válido para Visual Studio 2008
Definir
una clase
En Visual Basic 2008, todo el código que queramos escribir, lo
tendremos que
hacer en un fichero con la extensión .vb, dentro de ese fichero es donde
escribiremos nuestro código, el cual, tal como dijimos
anteriormente siempre
estará incluido dentro de una clase, aunque un fichero de código
de VB puede
contener una o más clases, es decir, no está limitado a una clase
por fichero.
En Visual Basic 2008 las clases se definen usando la palabra clave
Class seguida
del nombre de la clase, esa definición acaba indicándolo con End Class.
En el siguiente ejemplo definimos una clase llamada Cliente que
tiene dos campos
públicos.
Class Cliente
Public Nombre As String
Public Apellidos As String
End Class
Una vez definida la clase podemos agregar los elementos (o
miembros) que
creamos conveniente.
En el ejemplo anterior, para simplificar, hemos agregado dos
campos públicos,
aunque también podríamos haber definido cualquiera de los miembros
permitidos
en las clases.
Una clase especial: Module
En Visual Basic 2008 también podemos definir una clase especial
llamada Module,
este tipo de clase, como veremos, tiene un tratamiento especial.
La definición se hace usando la instrucción Module seguida del nombre a usar y
acaba con End Module.
Cualquier miembro definido en un Module siempre estará accesible en todo el
proyecto y para usarlos no tendremos que crear ningún objeto en
memoria.
Las clases definidas con la palabra clave Module realmente equivalen a las clases
en las que todos los miembros están compartidos y por tanto
siempre disponibles
a toda la aplicación.
De todos estos conceptos nos ocuparemos en las siguientes
lecciones, pero es
necesario explicar que existe este tipo de clase ya que será el
tipo de da tos que el
IDE de Visual Basic 2008 usará al crear aplicaciones del tipo
consola, ya que ese
será el tipo de proyecto que crearemos para practicar con el
código mostrado en
este primer módulo.
Los miembros de una clase
Una clase puede contener cualquiera de estos elementos (miembros):
· Enumeraciones
· Campos
· Métodos (funciones o procedimientos)
· Propiedades
· Eventos
Las enumeraciones,
como vimos en la lección anterior, podemos usarlas para
definir valores constantes relacionados, por ejemplo para indicar
lo s valores
posibles de cualquier "característica" de la clase.
Los campos son variables
usadas para mantener los datos que la clase
manipulará.
Los métodos son las
acciones que la clase puede realizar, normalmente esas
acciones serán sobre los datos que contiene. Dependiendo de que el
método
devuelva o no un valor, podemos usar métodos de tipo Function o de tipo Sub
respectivamente.
Las propiedades son
las "características" de las clases y la forma de acceder
"públicamente" a los datos que contiene. Por ejemplo,
podemos considerar que el
nombre y los apellidos de un cliente son dos características del
cliente.
Los eventos son mensajes
que la clase puede enviar para informar que algo está
ocurriendo en la clase.
Características de los métodos y propiedades
Accesibilidad,
ámbito y miembros compartidos
Aunque estos temas los veremos en breve con más detalle, para
poder
comprender mejor las características de los miembros de una clase
(o cualquier
tipo que definamos), daremos un pequeño adelanto sobre estas
caract erísticas que
podemos aplicar a los elementos que definamos.
Accesibilidad y ámbito son dos conceptos que están estrechamente
relacionados.
Aunque en la práctica tienen el mismo significado, ya que lo que
representan es la
"cobertura" o alcance que tienen los miembros de las
clases e incluso de las
mismas clases que definamos.
Si bien cada uno de ellos tienen su propia "semántica",
tal como podemos ver a
continuación:
Ámbito
Es el alcance que la definición de un miembro o tipo puede tener.
Es decir, cómo
podemos acceder a ese elemento y desde dónde podemos accederlo.
El ámbito de un elemento de código está restringido por el
"sitio" en el que lo
hemos declarado. Estos sitios pueden ser:
· Ámbito de bloque: Disponible
únicamente en el bloque de código en el que
se ha declarado.
· Ámbito de procedimiento: Disponible
únicamente dentro del
procedimiento en el que se ha declarado.
· Ámbito de módulo: Disponible
en todo el código del módulo, la clase o la
estructura donde se ha declarado.
· Ámbito de espacio de nombres: Disponible en todo el código del espacio
de nombres.
Accesibilidad
A los distintos elementos de nuestro código (ya sean clases o
miembros de las
clases) podemos darle diferentes tipos de accesibilidad. Estos
tipos de "acceso"
dependerán del ámbito que queramos que tengan, es decir, desde
dónde
podremos accederlos.
Los modificadores de accesibilidad son:
· Public: Acceso no restringido.
· Protected: Acceso
limitado a la clase contenedora o a los tipos derivados de
esta clase.
· Friend: Acceso limitado al proyecto actual.
· Protected Friend: Acceso
limitado al proyecto actual o a los tipos derivados
de la clase contenedora.
· Private: Acceso limitado al tipo contenedor.
Por ejemplo, podemos declarar miembros privados a una clase, en
ese caso,
dichos miembros solamente los podremos acceder desde la propia
clase, pero no
desde fuera de ella.
Nota:
Al declarar una variable con Dim, el ámbito que le estamos aplicando
por regla general, es privado, pero como veremos, en Visual Basic
2008 el ámbito puede ser diferente a privado dependiendo del tipo
en
el que declaremos esa variable.
Miembros
compartidos
Por otro lado, los miembros compartidos de una clase o tipo, son
elementos que
no pertenecen a una instancia o copia en memoria particular, sino
que pertenecen
al propio tipo y por tanto siempre están accesibles o disponibles,
dentro del nivel
del ámbito y accesibilidad que les hayamos aplicado, y su tiempo de vida es el
mismo que el de la aplicación.
Del ámbito, la accesibilidad y los miembros compartidos nos
ocuparemos c on más
detalle en una lección posterior, donde veremos ciertas
peculiaridades, como
puede ser la limitación del ámbito de un miembro que aparentemente tiene una
accesibilidad no restringida.
Parámetros
específicos y parámetros opcionales
En Visual Basic 2008, tanto los miembros de una clase, (funciones
y métodos
Sub), como las propiedades pueden recibir parámetros. Esos
parámetros pueden
estar explícitamente declarados, de forma que podamos indicar
cuantos
argumentos tendremos que pasar al método, también p odemos
declarar
parámetros opcionales, que son parámetros que no hace falta
indicar al llamar a la
función o propiedad, y que siempre tendrán un valor
predeterminado, el cual se
usará en caso de que no lo indiquemos.
Además de los parámetros específicos y opcionales, podemos usar un
array de
parámetros opcionales, en los que se puede indicar un número
variable de
argumentos al llamar a la función que los define, esto lo veremos
en la siguiente
sección.
Nota: Sobre parámetros y argumentos
Para clarificar las cosas, queremos decir que los parámetros son
los
definidos en la función, mientras que los argumentos son los
"parámetros" que pasamos a esa función cuando la
utilizamos desde
nuestro código.
Con los parámetros opcionales lo que conseguimos es permitir qu e
el usuario no
tenga que introducir todos los parámetros, sino solo los que
realmente necesite,
del resto, (los no especificados), se usará el valor
predeterminado que hayamos
indicado, porque una de las "restricciones" de este tipo
de parámetros, es que
siempre debemos indicar también el valor por defecto que debemos
usar en caso
de que no se especifique.
Veamos unos ejemplo para aclarar nuestras ideas:
Function Suma(n1 As Integer, Optional n2 As Integer = 15) As
Integer
Suma = n1 + n2
End Function
En este primer ejemplo, el primer parámetro es obligatorio
(siempre debemos
indicarlo) y el segundo es opcional, si no se indica al llamar a
esta función, se
usará el valor 15 que es el predeterminado.
Para llamar a esta función, lo podemos hacer de estas tres formas:
' 1-
indicando los dos parámetros (el resultado será 4= 1 + 3)
t = Suma(1,
3)
' 2-
Indicando solamente el primer parámetro (el resultado será
16= 1 +
15)
t = Suma(1)
' 3-
Indicando los dos parámetros, pero en el opcional usamos el
nombre
t = Suma(1,
n2:= 9)
El tercer ejemplo solamente tiene utilidad si hay más de un
parámetro opcional.
Nota:
Los parámetros opcionales deben aparecer en la lista de parámetros
del método, después de los "obligatorios"
Nota:
En el caso hipotético y no recomendable de que no estemos usando
Option Strict On, tanto los parámetros normales como los
opcionales
los podemos indicar sin el tipo de datos, pero si en alguno de
ellos
especificamos el tipo, debemos hacerlo en todos.