Sunteți pe pagina 1din 18

Delegacin de cdigo y eventos

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.

Al instanciar un delegado, se asocia con un mtodo de instancia o compartido de un objeto, y


posteriormente, durante la ejecucin, ser el delegado el que se encargue de ejecutar dicho mtodo y
no el propio objeto. Tambin se pueden asociar los delegados con procedimientos Sub o Function
de mdulos.

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()

' delegado con parametros Public Delegate Sub


Aviso(ByVal lsTexto As String)

' delegado de tipo function


Public Delegate Function Obtener(ByVal ldtFecha As Date) As String

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()

' Modo 1 -----------------------------


Sub Main() ' declarar un delegado Dim loDelegTexto As VerMensaje
' obtener la direccin del procedimiento a ejecutar ' y asignarla al delegado loDelegTexto =
AddressOf MostrarTexto

' ejecutar el procedimiento a travs del delegado loDelegTexto.Invoke()


End Sub

' Modo 2 -----------------------------


Sub Main() ' declarar el delegado y asociar con una direccin ' o puntero a un
procedimiento Dim loDelegTexto As New VerMensaje(AddressOf MostrarTexto)
loDelegTexto.Invoke()
End Sub

' *********************************************** ' este ser el procedimiento invocado


(ejecutado) ' por el delegado Public Sub MostrarTexto()
Console.WriteLine("Hola, esto es una prueba con delegados") End Sub End

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.

Si delegamos un procedimiento que admite parmetros, a la hora de invocarlo con el delegado,


debemos pasar al mtodo Invoke( ) los valores de los parmetros, en el mismo orden que
especifica el procedimiento. Veamos el ejemplo del Cdigo fuente 327.
Module Module1 Public Delegate Sub Aviso(ByVal
lsTexto As String)

Sub Main() Dim loGestionarAviso As Aviso

loGestionarAviso = New Aviso(AddressOf Normal) loGestionarAviso.Invoke("Recuerda


apagar el servidor")

loGestionarAviso = New Aviso(AddressOf Urgente) loGestionarAviso.Invoke("Realizar la


copia de seguridad")

Console.ReadLine() End Sub

Public Sub Normal(ByVal lsTexto As String)


Console.WriteLine("* {0} *", lsTexto) End Sub Public Sub Urgente(ByVal lsTexto As String)

Console.WriteLine(" {0} !!!", lsTexto.ToUpper) End Sub End


Module

Cdigo fuente 327


En el caso de delegacin hacia funciones, cuando invoquemos el cdigo con el delegado,
deberemos obtener el valor de retorno de la funcin. Veamos el ejemplo del Cdigo fuente 328.

Module Module1 Public Delegate Function Obtener(ByVal ldtFecha As


Date) As String

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

' como el delegado ejecuta funciones, recuperamos el valor ' de retorno al


invocar la funcin correspondiente lsResultado = loManipFecha.Invoke(ldtFecha)
Console.WriteLine("El resultado obtenido es: {0}", lsResultado)

Console.ReadLine() End Sub

Public Function RecuperaMes(ByVal ldtFecha As Date) As String Return


ldtFecha.ToString("MMMM") End Function

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

' en este procedimiento uno de los parmetros es un delegado '


y el otro el valor que utilizar el delegado como parmetro Public Sub
Gestionar(ByVal loDelObtener As Obtener, _
ByVal ldtUnaFecha As Date)

Dim lsResultado As String lsResultado = loDelObtener.Invoke(ldtUnaFecha)


Console.WriteLine("El resultado obtenido es: {0}", lsResultado)
End

Extender las funcionalidades de una clase a travs de


delegados
Supongamos que hemos creado una clase, con el nombre ManipFecha, que tiene una propiedad a
la que asignamos una fecha, y un mtodo que devuelve la fecha formateada. Ver el Cdigo fuente
330.
Module Module1
Sub Main() Dim loManipFecha As ManipFecha loManipFecha = New ManipFecha()
loManipFecha.Fecha = #6/27/2002 7:40:00 PM# Console.WriteLine("Fecha larga: {0}",
loManipFecha.DevFechaLarga())

Console.ReadLine() End Sub End

Public Class ManipFecha


Private mdtFecha As Date

Public Sub New() mdtFecha = Date.Now End Sub


Public Property Fecha()
As Date Get
Return
mdtFecha End
Set(ByVal Value As Date)
mdtFecha = Value
End Set
End Property
Public Function DevFechaLarga() As String
Return mdtFecha.ToLongDateString()
End Function
End Class

Despus de finalizar el desarrollo de la clase y distribuirla, se presenta el siguiente problema:


los programadores que la utilizan, disponen de rutinas de formateo propias que necesitaran
implementar en nuestra clase.

Este punto, evidentemente, lo podramos resolver utilizando herencia; no obstante, vamos a


solucionar el problema mediante delegados. Por lo tanto, aadiremos un delegado a la clase
ManipFecha, y un mtodo que lo invoque; al ejecutar este mtodo, le pasaremos la direccin del
procedimiento que contiene la rutina personalizada de formateo. Ver Cdigo fuente 331.
Module Module1
Sub Main() ' crear un objeto de la clase Dim loManipFecha As ManipFecha loManipFecha =
New ManipFecha() loManipFecha.Fecha = #6/27/2002 7:40:00 PM#

' 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

' este es un procedimiento que contiene una rutina


' personalizada de formateo, y que ser invocado
' desde el delegate del objeto
Public Function ObtenerHora(ByVal ldtFecha As Date) As String
Return ldtFecha.ToString("H:m")
End Function
End Module
Public Class ManipFecha
' ....
' ....
' declarar un delegado, a travs del cual,
' ejecutaremos rutinas de cdigo externas a la clase
Public Delegate Function RealizaFormato(ByVal ldtFecha As Date) As String
' ....
' ....
' este mtodo utiliza un delegado pasado como
' parmetro para invocar a un procedimiento externo
' a la clase

Public Function FormateoExterno(ByVal loDelegFormat As RealizaFormato) As


String
Return loDelegFormat.Invoke(mdtFecha)
End Function
End Class

No obstante, si disponemos de un conjunto ms extenso de rutinas de formateo, lo mejor es


aglutinarlas todas en mtodos de una clase, invocando a estos mtodos desde la clase que contiene
el delegado.

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

Para conseguir, ya en Main( ), que el delegado de la clase ManipFecha ejecute el cdigo de la


clase Formatos, podemos utilizar dos tcnicas.

Por un lado, instanciamos un objeto de Formatos, y pasamos al mtodo FormateoExterno( ),


del objeto ManipFecha, la direccin del mtodo Marinero( ) del objeto Formatos.

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.

Programacin estrictamente procedural


Antes de la llegada de los sistemas y lenguajes orientados a eventos, las aplicaciones ejecutaban su
cdigo en un orden fijo, ya que estaban basadas en un modelo construido exclusivamente a base
de procedimientos: se realizaban llamadas a las rutinas de cdigo en un orden predeterminado, y
una vez terminada la ejecucin de tales rutinas, finalizaba la aplicacin.

Un escenario de trabajo sin eventos


Supongamos que nos encargan desarrollar una clase llamada Empleado, entre cuyos miembros
tenemos la propiedad Sueldo. Uno de los requerimientos respecto a esta propiedad es que su
valor no debe ser superior a 1000; por ello, en su procedimiento Property, realizamos una
validacin a tal efecto, emitiendo un mensaje cuando el sueldo que asignemos sea superior. Ver el
Cdigo fuente 334.

variables de propiedad
Private msNombre As String
Private mdbSueldo As Double

' propiedad Nombre Public Property Nombre() As String Get


Return msNombre End Get Set(ByVal Value As String)
msNombre = Value End Set End Property

' propiedad Sueldo


Public Property Sueldo() As Double
Get
Return mdbSueldo
End Get

' al asignar un valor a la propiedad,


' si el valor es superior a 1000
' mostrar un mensaje y no permitir la
' asignacin del sueldo Set(ByVal Value As Double)
If Value > 1000 Then
Console.WriteLine("Asignacin de sueldo incorrecta")
Console.ReadLine()
Else
mdbSueldo = Value
End If
End Set
End Property
End Class

Una vez finalizado el desarrollo de la clase, la distribuimos a nuestro cliente. Posteriormente,


un nuevo cliente nos requiere la clase, pero en esta ocasin, aunque necesita la validacin sobre la
propiedad Sueldo, no quiere que se muestre el mensaje al sobrepasar el sueldo asignado.

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.

Programacin basada en eventos


La aparicin de Windows trajo consigo un nuevo esquema en el desarrollo de aplicaciones.
En un programa que se ejecute dentro de un sistema basado en eventos como pueda ser
Windows, se estn produciendo constantemente eventos (sucesos), provocados por las acciones
del usuario o por el propio sistema. Tan elevado es el nmero de eventos que se producen, que dar
respuesta a todos, es decir, codificar todas aquellas situaciones que acontecen a lo largo de la
ejecucin de un programa, es algo impensable.

Esquema bsico de un sistema orientado a eventos


Un sistema conducido por eventos basa su funcionamiento en dos pilares fundamentales: un
emisor y un receptor de 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.

Enlace esttico de eventos


Este es el modo mas sencillo para implementar la conexin entre un evento y un
procedimiento manipulador de evento.

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

Private WithEvents moEmple As Empleado '...... '......

Conexin de un emisor de eventos con un


manipulador de eventos
Existen dos medios para comunicar un evento con un manipulador de eventos:

. En tiempo de compilacin, realizando un enlace esttico entre la clase y el manipulador


mediante las palabras clave WithEvents y Handles. Esta tcnica tiene la ventaja de que permite
escribir un cdigo mucho ms legible, en cuanto a la manipulacin de eventos se refiere.
. En tiempo de ejecucin, realizando un enlace dinmico entre la clase y el manipulador
mediante la palabra clave AddHandler. La ventaja en este caso, es que podemos asociar
procedimientos manipuladores de evento dinmicamente durante el transcurso de la ejecucin del
programa.

Enlace dinmico de eventos


Siendo un poco ms complejo a nivel sintctico que el enlace esttico, el enlace dinmico de
eventos a sus correspondientes manipuladores, tiene la ventaja de que nos permite asociar el mismo
evento a diferentes procedimientos manipuladores de dicho evento, durante el transcurso de la
ejecucin del programa.

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.

La clase EventArgs, o cmo obtener informacin del objeto


emisor del evento
En los ejemplos sobre captura de eventos realizados hasta ahora con la clase Empleado, dentro de
los procedimientos manipuladores de evento, no disponemos de acceso a los miembros del objeto
que ha originado el evento.
El nico modo de los vistos hasta ahora de conseguir tal acceso, es declarar el objeto en la
zona de declaraciones del mdulo y, en ese caso, al tener visibilidad sobre la variable del objeto en
todos los procedimientos del mdulo, s podramos manejar el objeto.

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"

' pasar un valor del array a una variable

Dim sValor As String sValor = sNombres(2)

' mostrar en la consola el valor pasado a una variable


' y un valor directamente desde el array
Console.WriteLine("Valor de la variable sValor: {0}", sValor)
Console.WriteLine("Valor del array, posicin 1: {0}", sNombres(1))
Console.ReadLine()
End Sub

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.

El primer ndice de un array debe ser siempre cero


VB.NET no soporta la instruccin Option Base, que nos permita indicar que el primer ndice de un
array poda ser cero o uno. Por lo tanto, al declarar ahora un array en VB.NET, su nmero de
elementos ser el indicado en la declaracin ms uno. Veamos las diferencias en el Cdigo fuente
351.
Cdig
o VB6
=======
=== Option
Base 1

Public Sub Main()


Dim sNombres(2) As String
sNombres(1) = "Pedro"
sNombres(2) = "Ana" End Sub

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

No es posible crear arrays con rangos de ndices


La caracterstica que en VB6, nos permita declarar un array en el que sus ndices estuvieran en un
intervalo, tampoco se admite ya en VB.NET. Al tener los arrays que comenzar por cero en su primer
ndice, los rangos de ndices han dejado de tener sentido. Ver Cdigo fuente 352.

Cdigo VB6, no soportado en


VB.NET
======================
============ Public Sub Main()
' array de 4 elementos, entre los
' ndices 5 y 8
Dim Nombres(5 To 8) As String
Nombres(5) = "Pedro"
Nombres(6) = "Ana"
Nombres(7) = "Jaime"
Nombres(8) = "Elena" End Sub

Todos los arrays son dinmicos


En VB6, dependiendo del modo de creacin de un array, este poda ser esttico, es decir, con
un nmero fijo e invariable de elementos; o bien dinmico, es decir, su nmero de elementos poda
ser modificado en tiempo de ejecucin.
En VB.NET sin embargo, todos los arrays son de tamao variable, tanto si se especifica como no un
tamao al ser declarados. En este punto debemos matizar un aspecto: cada vez que en VB.NET se
cambia el tamao de un array, el entorno internamente destruye el array actual, y crea un nuevo
objeto de la clase Array, con el nuevo tamao especificado, usando el mismo nombre de la variable
correspondiente al array eliminado en primer lugar.

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( ).

Paso de arrays como parmetros, y devolucin desde


funciones
Podemos pasar un array como parmetro a una rutina de cdigo, teniendo en cuenta que los
cambios que realicemos sobre el array en el procedimiento llamado, se mantendrn al volver el flujo
de la ejecucin al procedimiento llamador.

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

' a este procedimiento le pasamos un array por valor


Private Sub ManipArrayVal(ByVal iListaPorValor As Integer())
' cambiar elemento del array iListaPorValor(0) = 888
End
' a este procedimiento le pasamos un array por referencia
Private Sub ManipArrayRef(ByRef iListaPorReferencia As Integer()) '
cambiar elemento del array iListaPorReferencia(2) = 457
End
Private Sub MostrarArray(ByVal sMiLista() As Integer) '
muestra el array pasado como parmetro Dim iContador As
Integer For iContador = 0 To sMiLista.Length - 1
Console.WriteLine("Elemento: {0} - Valor: {1}", _
iContador, sMiLista(iContador)) Next Console.WriteLine()
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

referencia que apuntan al mismo conjunto de valores.


Podemos clonar el array, como se ha descrito en el apartado anterior, con lo que obtendremos
un nuevo array, que ser idntico al original.

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

' recorrer un array de objetos


Private Sub MostrarArrayObj(ByVal oMiLista() As Object) Dim iContador As Integer For
iContador = 0 To oMiLista.Length - 1
Console.WriteLine("Elemento: {0} - Valor: {1}", _
iContador, oMiLista(iContador)) Next Console.WriteLine()
End

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

Private Sub MostrarArray(ByVal sMiLista() As String)


Dim iContador As Integer For iContador = 0 To
sMiLista.Length - 1
Console.WriteLine("Elemento: {0} - Valor: {1}", _
iContador, sMiLista(iContador)) Next Console.WriteLine()
End

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"))

' buscar una cadena a partir del ndice 3 del array


Console.WriteLine("Ana est en la posicin {0}," & _ " comenzando a buscar desde ndice
3", _ Array.IndexOf(sNombres, "Ana", 3))

' 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))

Console.ReadLine() End Sub

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.

Si declaramos un array del modo que muestra el Cdigo fuente 364.

Dim iDatos(2, 4) As Integer


Crearamos un array multidimensional formado por tres filas y cinco columnas. En este caso,
el nmero correspondiente a la primera dimensin denota las filas, mientras que el nmero de la
segunda dimensin hace lo propio para las columnas. La Figura 209 muestra un diagrama con la
estructura de este array.
Figura 209. Estructura de un array multidimensional.
En este tipo de arrays, para acceder a los valores, debemos especificar la dimensin y la posicin a
la que vamos a asignar o recuperar un dato. Ver Cdigo fuente 365.
Sub Main()
' crear array multidimensional y rellenar de valores
Dim iDatos(2, 4) As Integer
iDatos(0, 0) = 1000

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

S-ar putea să vă placă și