Documente Academic
Documente Profesional
Documente Cultură
Delegados (delegates)
Un delegado o delegate, es un objeto al que otros objetos ceden (delegan) la ejecucin de su
cdigo. Tambin se conocen como punteros a funcin con seguridad de tipos.
Declaracin de delegados
Para declarar un delegado, debemos utilizar la palabra clave Delegate, seguida del tipo de mtodo
(Sub o Function) al que posteriormente deberemos asociar el delegado; y finalmente, el nombre del
delegado con la lista de parmetros y valor de retorno si es necesario. El lugar de declaracin debe
ser la zona de declaraciones de la clase o mdulo. Veamos unos ejemplos en el Cdigo fuente 324.
' delegado sin parmetro
Public Delegate Sub VerMensaje()
Para que el lector pueda reproducir los ejemplos mostrados en este tema, abra un nuevo proyecto
de tipo aplicacin de consola en VS.NET.
Creacin de delegados
Seguidamente, y ya en un procedimiento, declaramos una variable correspondiente al tipo del
delegado. A continuacin, conectamos el delegado con el procedimiento que posteriormente deber
ejecutar, empleando la palabra clave AddressOf, seguida del nombre del procedimiento.
AddressOf devuelve el puntero o direccin de entrada al procedimiento, que ser lo que utilice el
delegado para saber la ubicacin del procedimiento que debe ejecutar. Por ltimo, para ejecutar el
procedimiento al que apunta el delegado, llamaremos a su mtodo Invoke( ). En el Cdigo fuente
325, se muestran dos tcnicas para crear un delegado; la segunda es mucho ms simple, pero en
ambas, el resultado es el mismo: la ejecucin indirecta del procedimiento MostrarTexto( ), a travs
del delegado.
Public Delegate Sub VerMensaje()
Una de las ventajas de este tipo de entidades de la plataforma, consiste en que un mismo delegado
puede llamar a mtodos diferentes de objetos distintos. En el caso del Cdigo fuente 326, un
delegado invoca a dos procedimientos diferentes.
Sub Main() ' obtener una fecha Dim ldtFecha As Date Console.WriteLine("Introducir una
fecha") ldtFecha = Console.ReadLine()
' crear un delegado, y segn el mes de la fecha obtenida, ' el delegado ejecutar una
funcin determinada Dim loManipFecha As Obtener Dim lsResultado As String If ldtFecha.Month
< 6 Then
loManipFecha = AddressOf RecuperaMes Else loManipFecha = AddressOf
DameDiaSemana End If
Public Function DameDiaSemana(ByVal ldtFecha As Date) As String Return ldtFecha.ToString("dddd") End Function End
Module
Aunque en los anteriores ejemplos, hemos invocado los delegados desde el mismo procedimiento
en que han sido creados, podemos, naturalmente, pasar un delegado como parmetro a un
procedimiento, y que sea dicho procedimiento el encargado de ejecutar el cdigo que guarda el
delegado. De esta forma, si el anterior ejemplo lo variamos ligeramente, y aadimos un
procedimiento que reciba el delegado y el parmetro, obtendramos el Cdigo fuente 329.
Sub Main() ' ...... ' ...... ' llamar a un procedimiento que
ejecuta el delegado Gestionar(loManipFecha, ldtFecha) ' ......
' ......
End Sub
' llamar ahora al mtodo que ejecuta un delegate; ' le pasamos a este mtodo la
direccin del ' procedimiento que el delegate debe invocar Dim lsFormatoResultado As String
lsFormatoResultado = loManipFecha.FormateoExterno(AddressOf ObtenerHora)
Console.WriteLine("Formateo externo resultante: {0}", lsFormatoResultado)
Console.ReadLine()
End
El Cdigo fuente 332 muestra la clase Formatos, en la que hemos creado dos mtodos que realizan
operaciones de formato.
Public Class Formatos
' los mtodos de esta clase, reciben una fecha a la que
' aplican un formato y devuelven una cadena con el
' formato resultante Public Function Marinero(ByVal ldtFecha As Date)
As String
Return ldtFecha.ToString("Cua\derno \de bi\tcora: " & _
"en el ao yyyy, dd \de MMMM") End Function
Shared Function Espacial(ByVal ldtFecha As Date) As String Return ldtFecha.ToString("Diario e\s\telar: " & _ "MMM-d-
yyyy / Sec\tor Ga\m\ma") End Function End
Por otra parte, en lo referente al mtodo Espacial( ) de la clase Formatos, no es necesario crear un
objeto. Debido a que dicho mtodo es compartido, podemos pasar su direccin al mtodo
FormateoExterno( ), del objeto ManipFecha.
Eventos. Qu es un evento?
Un evento es un suceso o situacin, que acontece en una ubicacin de espacio y tiempo no
predecible.
Cuando una mquina deja de funcionar por una avera, o cuando una persona resbala y cae,
estamos en ambos casos, ante ejemplos de eventos, ya que ocurren en momentos inesperados.
Para que se desencadene un evento, se deben dar determinadas circunstancias, las cuales favorecen
el que dicho evento se produzca.
Eventos en .NET
Cindonos al mbito de la programacin, un evento es, dentro de una aplicacin, una notificacin
lanzada por un objeto, que podr ser respondida por aquellos otros objetos interesados en darle
soporte.
variables de propiedad
Private msNombre As String
Private mdbSueldo As Double
Se nos plantea en este caso un problema, ya que si escribimos una nueva versin de la clase
Empleado, tendremos el trabajo extra de mantener ambas. Para solucionarlo mediante una nica
versin de la clase recurriremos a los eventos.
El primero genera y lanza el evento al sistema, mientras que el segundo, si est interesado en
tratar el evento lanzado, lo captura y le da respuesta. Si un objeto receptor no necesita gestionar
eventos, simplemente no lo obtiene. Ver Figura 206.
El emisor de eventos
Un emisor de eventos, tambin denominado origen de eventos (event source o event sender),
es un objeto capacitado para generar y lanzar eventos al sistema, que puedan ser recuperados por
otros objetos preparados para realizar su tratamiento.
Para que un objeto pueda desencadenar eventos, en su clase debemos realizar dos tareas:
. Declarar el propio evento usando la palabra clave Event, especificando si es necesario una
lista de parmetros que acompaan al evento.
. Lanzar el evento mediante la palabra clave RaiseEvent, seguida del nombre del evento a
disparar. Si hemos declarado el evento con parmetros, deberemos aadir los valores para cada uno
de los parmetros en el mismo orden en el que los hemos declarado.
El receptor de eventos
Un receptor de eventos, tambin denominado manipulador de eventos (event receiver o event
handler), es aquella parte del cdigo cliente, que configuramos para que sea capaz de recibir los
eventos generados por un objeto emisor. Para que ambos elementos, en este canal de comunicacin
que es la transmisin de eventos puedan operar, es necesario conectarlos.
En primer lugar, declaramos una variable del tipo de objeto cuyos eventos queremos capturar,
en la zona de declaraciones del mdulo, clase, etc., utilizando la palabra clave WithEvents. Veamos
el Cdigo fuente 336.
Module Module1
Por lo tanto, en el mdulo de cdigo donde tenemos a Main( ), vamos a escribir dos procedimientos
que asociaremos dinmicamente al evento que hemos creado en la clase Empleado. Ver Cdigo
fuente 341.
Un evento es un delegado
Cuando declaramos en una clase, un evento con la instruccin Event, se crea de modo transparente
para el programador, un nuevo delegado con el nombre del evento ms la palabra EventHandler.
Sin embargo, qu ocurre cuando instanciamos un objeto Empleado con mbito local en
Main( ), y asociamos sus manipuladores de evento con AddHandler?. Simplemente, que desde
dichos procedimientos manipuladores de evento, no podemos obtener informacin del objeto
Empleado para, por ejemplo, recuperar el valor de la propiedad Nombre.
Una solucin simple, pero no eficaz, consistira en pasar la/s propiedad/es como parmetro cuando
lanzamos el evento, es decir, al llamar a RaiseEvent( ) en la clase Empleado. Ver Cdigo fuente
346.
Public Class
Empleado
'....
RaiseEvent LimiteSueldo(Value,Me.Nombre)
'.... End Class
Arrays
Aspectos bsicos
Tambin conocido con las denominaciones de matriz y vector, un array es aquel elemento del
lenguaje que nos permite agrupar un conjunto de valores del mismo tipo, y acceder a ellos a travs
de una misma variable o identificador, especificando la posicin o ndice en donde se encuentra el
dato a recuperar. El Cdigo fuente 350, muestra las operaciones esenciales que podemos realizar
con un array.
Sub Main()
' declarar un array de tipo String,
' el nmero de elementos es el indicado
' en la declaracin ms uno, porque la primera ' posicin
de un array es cero
Dim sNombres(3) As String
'asignar valores al array
sNombres(0) = "Ana"
sNombres(1) = "Pedro"
sNombres(2) = "Antonio"
sNombres(3) = "Laura"
A lo largo de este texto, emplearemos de forma genrica el trmino array, para referirnos a este
elemento del lenguaje. Por otra parte, recomendamos al lector la creacin de un nuevo proyecto
en el IDE de tipo consola, para realizar las pruebas mostradas a lo largo del tema.
La clase Array
Esta clase, perteneciente a la jerarqua de clases del sistema, es decir, incluida en el espacio
de nombres System, proporciona a travs de sus miembros, acceso orientado a objeto para los
arrays que manipulemos en nuestras aplicaciones. Esto quiere decir que los arrays, como sucede con
otros elementos del lenguaje, son tambin objetos.
Al igual que el resto de elementos del entorno, los arrays son tipos pertenecientes al sistema
comn de tipos de la plataforma o CTS, y se encuentran clasificados como tipos por referencia; esto
quiere decir, que durante la ejecucin, un array ser gestionado en la zona de memoria conocida
como montn o heap.
Aunque podemos trabajar con los arrays como objetos, no ser necesario instanciar un objeto de
esta clase para poder disponer de un array. Al declarar una variable como array, implcitamente se
instancia un objeto de la clase. En sucesivos apartados de este tema, haremos una descripcin de los
miembros de instancia y compartidos ms importantes de la clase Array.
Adecuacin de los arrays en VB con los arrays de la
plataforma .NET
Los arrays son uno de los elementos de VB que menos han evolucionado a lo largo de las
sucesivas versiones aparecidas de este lenguaje. Todo esto, sin embargo, ha cambiado con la llegada
de la plataforma .NET.
La especificacin CLS del entorno .NET, dicta que todos los lenguajes que cumplan con la
misma, podrn ser utilizados bajo .NET Framework. Esto quiere decir adems, que dos
ensamblados escritos en distintos lenguajes de la plataforma, podrn compartir cdigo entre ellos.
En el caso que nos ocupa, una aplicacin VB.NET podr llamar a un mtodo de un objeto escrito en
C# que devuelva un array, y dicho array, ser manejado desde VB.NET.
Los diseadores de .NET han realizado un gran esfuerzo en proporcionar la mxima optimizacin y
versatilidad a los arrays, siempre y cuando, el lenguaje del entorno que los utilice, cumpla con unos
mnimos requerimientos. En este aspecto, VB.NET como lenguaje, ha obtenido toda la potencia de
base inherente en el sistema para la creacin y manipulacin de arrays; mientras que como
contrapartida, ciertas caractersticas exclusivas en VB para el manejo de arrays han necesitado ser
readaptadas. Algunas de estas caractersticas se describen a continuacin.
Cdigo
VB.NET
==========
=== Public Sub
Main()
' array de 3 elementos
Dim sNombres(2) As String
sNombres(0) = "Pedro"
sNombres(1) = "Ana"
sNombres(2) = "Jaime" End Sub
Declaracin
Declararemos un array de igual forma que hacemos con una variable normal, con la excepcin de
que junto al nombre de la variable, situaremos unos parntesis. Esto indica que dicha variable
contiene un array. Opcionalmente, podemos especificar entre los parntesis las dimensiones del
array, o nmero de elementos que va a contener. Es posible tambin, realizar una asignacin de
valores al array en el mismo momento de su declaracin. El Cdigo fuente 353, muestra algunos
ejemplos.
Recomendamos al lector, que en estos ejemplos con arrays, utilice el depurador para ejecutar lnea
a lnea el cdigo, y abra la ventana Locales del depurador para ver en cada caso, el contenido de los
elementos del array.
Asignacin y obtencin de valores
Para asignar u obtener valores de los elementos de un array, emplearemos la variable que contiene
el array haciendo referencia al ndice o posicin a manipular. O bien, puesto que un array es un
objeto, utilizaremos los mtodos SetValue( ) y GetValue( ) que asignan y obtienen respectivamente
los valores del array. Veamos un ejemplo en el Cdigo fuente 354.
Sub Main()
' asignacin de valores a los elementos de un array
' =================================================
Dim sNombres(4) As String
' directamente sobre la variable,
' haciendo referencia al ndice sNombres(0) = "Juan" sNombres(1) = "Ana" sNombres(2) = "Luis" ' o con el mtodo
SetValue(), asignando el ' valor en el primer parmetro y especificando ' la posicin en el segundo
sNombres.SetValue("Elena", 3) sNombres.SetValue("Miguel", 4)
' obtencin de valores de un array
' ================================
Dim sValorA As String
Dim sValorB As String sValorA = sNombres(2)
' directamente de la variable sValorB = sNombres.GetValue(3)
' usando el meth GetValue Console.WriteLine("Contenido de las variables")
Console.WriteLine("==========================") Console.WriteLine("ValorA: {0}
-- ValorB: {1}", sValorA, sValorB) Console.ReadLine()
End
Recorrer el contenido
Para realizar un recorrido por los elementos de un array, disponemos de las funciones
LBound( ) y UBound( ), que devuelven el nmero de ndice inferior y superior respectivamente del
array que pasemos como parmetro. No obstante, la orientacin a objetos proporcionada por el
entorno, pone a nuestra disposicin el nuevo conjunto de caractersticas que comentamos
seguidamente.
. Length. Esta propiedad de un objeto array devuelve el nmero de elementos que contiene.
. GetLowerBound( ), GetUpperBound( ). Estos mtodos de un objeto array, devuelven
respectivamente, el nmero de ndice inferior y superior de una dimensin del array. El resultado es
el mismo que usando LBound( ) y UBound( ), pero desde una perspectiva orientada a objetos.
. Enumeradores. Un objeto enumerador pertenece al interfaz IEnumerator, diseado para
realizar un recorrido o iteracin a travs de uno de los diferentes tipos de coleccin (arrays
incluidos) existentes en .NET Framework. Mediante el mtodo GetEnumerator( ) de un objeto
array, obtenemos un objeto que implementa el interfaz Ienumerator, que slo puede realizar labores
de lectura sobre el array, en ningn caso de modificacin.
La estructura de control utilizada para recorrer el array, puede ser indistintamente un bucle
For...Next, For Each...Next, o la novedosa tcnica de los objetos enumeradores proporcionados por
el objeto array.
Como muestra de estas funcionalidades, el Cdigo fuente 355 que vemos a continuacin, contiene
algunos ejemplos de cmo realizar una iteracin sobre los elementos de un array.
Modificacin de tamao
Para aumentar o disminuir el nmero de elementos de un array disponemos de la palabra clave
ReDim. Esta instruccin crea internamente un nuevo array, por lo que los valores del array original
se pierden.
Evitaremos este problema utilizando junto a ReDim la palabra clave Preserve, que copia en el
nuevo array, los valores del array previo. Veamos unos ejemplos en el Cdigo fuente 356.
Uso del mtodo CreateInstance( ) para establecer el
nmero de elementos en un array
Ya hemos comprobado que al crear un array en VB.NET, el primer ndice es siempre cero, y
adems, el nmero de elementos del array es el indicado en la declaracin ms uno.
Sin embargo, la clase Array dispone del mtodo compartido CreateInstance( ), que como su
nombre indica, permite crear una nueva instancia de la clase, es decir un objeto array, con la
particularidad de que en este caso, el nmero de elementos del array ser realmente el que
establezcamos al llamar a este mtodo.
El Cdigo fuente 357, muestra la diferencia entre crear un array del modo habitual, y empleando
CreateInstance( ).
Ello es debido a que los arrays son tipos por referencia del entorno, y por lo tanto, las
variables del array que manejamos tanto desde el procedimiento llamador, como desde el
procedimiento llamado, son en realidad punteros hacia una misma zona de memoria o referencia, la
que contiene el array.
En el ejemplo del Cdigo fuente 358, comprobaremos que al pasar un array por valor, los cambios
que realicemos sobre sus elementos se mantendrn al volver al procedimiento que hizo la llamada.
Sub Main()
Dim iValores() As Integer = {10, 20, 30}
' en ambos casos, se pasa una referencia del array
ManipArrayVal(iValores)
ManipArrayRef(iValores)
' al volver de las llamadas a los procedimientos,
' el array ha sido modificado en ambas llamadas, '
independientemente de que haya sido pasado por
' valor o referencia MostrarArray(iValores) Console.ReadLine()
End
Clonacin
Para evitar el problema planteado en el apartado anterior, si necesitamos disponer de un array
con las mismas caractersticas que uno ya existente, y que sea totalmente independiente del primero,
utilizaremos el mtodo Clone( ).
Con esto solucionaremos el problema de que al pasar un array como parmetro, las modificaciones
que precisemos realizar, afecten al array original. Veamos un ejemplo en el Cdigo fuente 359.
Sub Main()
' crear un array
Dim iValores() As Integer = {10, 20, 30}
CambiaArray(iValores)
Copia
variables que apuntan a la misma lista de valores, por lo que en definitiva slo tendremos un
array, al cual podremos acceder usando dos variables. Ello es debido a que como explicamos en un
apartado anterior, los arrays son tipos por
O bien, podemos copiar el array utilizando los mtodos CopyTo( ) y Copy( ) de la clase array. La
diferencia con respecto a la clonacin, consiste en que al copiar un array, el array destino ya debe
estar creado con el nmero suficiente de elementos, puesto que los mtodos de copia de la clase
Array, lo que hacen es traspasar valores de los elementos del array origen al array destino, en
funcin de los parmetros utilizados, copiaremos todos los elementos o un subconjunto. Veamos
unos ejemplos en el Cdigo fuente 360.
Inicializacin de valores
Para inicializar o eliminar los valores de los elementos de un array, utilizaremos el mtodo Clear, al
que pasaremos el array a inicializar, el ndice a partir del que comenzaremos, y el nmero de
elementos.
Los valores sern inicializados en funcin del tipo de dato del array; cadena vaca en arrays String;
cero en arrays numricos, etc Veamos el Cdigo fuente 361.
Sub Main()
' array String, asignar valores e inicializar Dim
sLetras(2) As String sLetras(0) = "a" sLetras(1) = "b"
sLetras(2) = "c"
' limpiar elementos en un array de tipo String, ' los
elementos limpiados quedan como cadena vaca
Array.Clear(sLetras, 0, 1)
Console.WriteLine("Array sLetras")
MostrarArray(sLetras)
' array Integer, asignar valores e inicializar Dim iNumeros() As Integer = {100, 200, 300,
400, 500, 600} ' limpiar elementos en un array de tipo Integer, ' los elementos limpiados se
ponen a 0 Array.Clear(iNumeros, 1, 2) Console.WriteLine("Array iNumeros")
MostrarArrayNum(iNumeros)
' array Object, asignar valores e inicializar Dim oVarios(6) As Object oVarios(0) = "Hola"
oVarios(1) = 456 oVarios(2) = 1200 oVarios(3) = #12/25/2001# oVarios(4) = 900 oVarios(5) =
True oVarios(6) = "adelante" ' al ser este un array de tipo Object ' los elementos limpiados se
establecen a Nothing Array.Clear(oVarios, 3, 2) Console.WriteLine("Array oVarios")
MostrarArrayObj(oVarios)
Console.ReadLine() End
' recorrer un array de nmeros
Private Sub MostrarArrayNum(ByVal iMiLista() As Integer) Dim iContador As Integer For
iContador = 0 To iMiLista.Length - 1
Console.WriteLine("Elemento: {0} - Valor: {1}", _
iContador, iMiLista(iContador)) Next Console.WriteLine()
End Sub
Ordenacin
Para ordenar un array disponemos del mtodo Sort( ), que al estar sobrecargado, tiene varias
implementaciones; la ms bsica de ellas es la que ordena la totalidad del array. Tambin podemos
ordenar una parte del array, indicando la posicin inicial y cantidad de elementos a ordenar, etc.
El mtodo Reverse( ), invierte la posicin de todos o parte de los elementos de un array. En este
punto, debemos matizar que no se realiza un orden inverso de los elementos, sino que se cambian
las posiciones de los mismos. Ver Cdigo fuente 362.
Sub Main() ' ordenar todo el array Dim sLetras1() As String = {"z", "a", "g",
"m", "w", "i", "c", "b"} Array.Sort(sLetras1) Console.WriteLine("Ordenar todos el
array") MostrarArray(sLetras1)
' ordenar parte del array Dim sLetras2() As String = {"z", "a", "g", "m", "w", "i", "c", "b"}
Array.Sort(sLetras2, 4, 3) Console.WriteLine("Ordenar parte del array") MostrarArray(sLetras2)
' invertir valores dentro del array Dim sLetras3() As String = {"z", "a", "g", "m", "w", "i", "c", "b"} Array.Reverse(sLetras3, 2,
4) Console.WriteLine("Invertir valores del array") MostrarArray(sLetras3)
Console.ReadLin
e() End Sub
Bsqueda
Los mtodos IndexOf( ) y LastIndexOf( ) de la clase Array, nos permiten buscar un elemento
en un array comenzando la bsqueda desde el principio o final respectivamente.
Ya que ambos disponen de diferentes implementaciones al estar sobrecargados, consulte el lector la
documentacin de la plataforma. El Cdigo fuente 363 muestra algunos ejemplos de uso.
Sub Main() Dim sNombres() As String = {"Alberto", "Juan", "Ana", "Paco", "Miguel",
"Ana"}
' buscar una cadena a partir del ndice 0 del array Console.WriteLine("Paco est en la
posicin {0}", _
Array.IndexOf(sNombres, "Paco"))
' introducir un valor a buscar en el array, ' si no existe se devuelve -1 Dim iPosicionBuscar
As Integer Console.WriteLine("Introducir nombre a buscar") iPosicionBuscar =
Array.IndexOf(sNombres, _
Console.ReadLine())
If iPosicionBuscar = -1 Then Console.WriteLine("El nombre no est en el array") Else Console.WriteLine("El nombre est
en la posicin {0} del array", _ iPosicionBuscar) End If
' buscar comenzando por la ltima posicin Dim iNumeros() As Integer Dim
iUltPosicionBuscar As Integer iNumeros = New Integer() {10, 20, 30, 10, 50, 60, 10, 70, 80}
Console.WriteLine("El 10 est en la posicin {0} comenzando por el final", _
Array.LastIndexOf(iNumeros, 10))
Arrays multidimensionales
Todos los arrays vistos hasta el momento han sido de tipo unidimensional, es decir, estaban
compuestos de una lista de valores nica.
.NET Framework nos provee tambin de la capacidad de crear arrays formados por ms de
una lista de valores, o lo que es igual, arrays multidimensionales. Un array de este tipo, se
caracteriza por estar compuesto de varias dimensiones o listas anidadas al estilo de filas y columnas.
iDatos(0, 1) = 2000
iDatos(0, 2) = 3000
iDatos(0, 3) = 4000
iDatos(0, 4) = 5000
iDatos(1, 0) = 25
iDatos(1, 1) = 35
iDatos(1, 2) = 45
iDatos(1, 3) = 55
iDatos(1, 4) = 65
iDatos(2, 0) = 111
iDatos(2, 1) = 222
iDatos(2, 2) = 333
iDatos(2, 3) = 444
iDatos(2, 4) =
555
End Sub