Vous êtes sur la page 1sur 6

18/06/2010 Delegados en .

NET - Parte I

Página de inicio Biblioteca Aprender Descargas Iniciar sesión | | Preferencias

Delegados en .NET - Parte I

Por Johann Granados

Contenido

1. Introducción (En el reino del desarrollo de software ...)


2. Delegados
3. Usos de los delegados
4. Definición e implementación de delegados
5. Ejemplos

1. Introducción (En el reino del desarrollo de software ...)

Antes del advenimiento de la plataforma .NET, Visual Basic era el rey (al menos en el reino del desarrollo de
software para plataforma Microsoft). Cerca del 80% de las aplicaciones de negocios a nivel mundial estaban
(y muchas siguen estando) escritas en ese lenguaje. Sin embargo, muchos programadores acostumbrados a
la complejidad -y flexibilidad- de lenguajes de más bajo nivel (como C++) criticaban a Visual Basic por no
permitir un mayor control sobre la forma en que se estructura y codifica el software. "Visual Basic es muy
tieso", decían. Y tenían razón. Visual Basic está orientado a la funcionalidad del producto (no a su
arquitectura). Lo anterior enfurecía a quienes deseaban un mayor control sobre los recursos de la máquina,
las estructuras de programación, e incluso sobre la propia forma en la que el código fuente se traduce a
código máquina. Con Visual Basic se podía crear aplicaciones mucho más rápido que en C++ (por ejemplo)
pero dichas aplicaciones rara vez era más eficientes, escalables e incluso portables que las escritas en
lenguajes de más bajo nivel. Con la llegada de la plataforma .NET, esta situación cambió.

.NET brinda al programador un mayor control sobre la forma en que su código accede a los recursos, utiliza
las estructuras y técnicas de programación e, incluso, se traduce a lenguaje intermedio (el lenguaje de la
plataforma .NET).

Este artículo se introduce en la discusión y aprendizaje de una serie de conceptos fundamentales en la


programación de aplicaciones para la plataforma .NET, los cuales es importante dominar si se desea sacar
verdadero provecho de las bondades de esta plataforma.

Principio de la página

2. Delegados

Un delegado es una estructura de programación que nos permite invocar a uno o varios métodos a la vez.
Estos métodos pueden encontrarse en la misma clase desde la que se invocan o en clases distintas asociadas
a ésta. Hablando "a bajo nivel", un delegado es un puntero seguro a una función (pero sin la complejidad de
la administración propia de dicho puntero).

Principio de la página

3. Usos de los delegados

Gestión de eventos
Quizás éste sea el principal uso de los delegados. Notificar a uno o varios componentes el acontecimiento de
un determinado evento con el fin de que dichos componentes tomen alguna acción al respecto. Este es el
fundamento de la programación orientada a eventos (uno de los pilares de la programación visual).
Utilizando eventos, los componentes de la interfaz avisan a la lógica de negocios que el usuario ha ejecutado
alguna acción sobre los componentes de la misma (por ejemplo, presionar el botón del mouse o presionar
una tecla).

msdn.microsoft.com/…/bb972282.aspx 1/6
18/06/2010 Delegados en .NET - Parte I
Implementación de patrones de diseño
Existen muchos patrones de diseño basados en eventos (posiblemente el más conocido sea el patrón
"Publicador-Suscriptor"). Utilizando eventos y delegados se puede establecer un mecanismo que permita
que una clase interesada en los servicios de otra reciba una notificación instantánea en el momento en que
acontezca un acontecimiento sobre el cual deba tomar alguna acción (por ejemplo, recibir una notificación
cuando se realice una operación sobre una cuenta bancaria).

Llamadas asíncronas
La invocación a un componente relacionado puede tomar mucho tiempo en recibir respuesta. Esto sucede
muchas veces cuando se manipulan grandes cantidades de datos o cuando la lógica del servicio que se
invoca es extremadamente compleja. Lo más "triste" de esta situación es que muchas veces no requerimos la
respuesta a dicha invocación para seguir trabajando, o bien, podemos realizar otras tareas mientras
esperamos por ella. En estos casos podemos pasar el puntero a una función ("Perdón ... ¿Dijo un delegado?")
para que en el momento en que el método invocado finalice su ejecución llame a la función que le fue pasada
(utilizando su dirección o puntero) con el fin de indicar que ha terminado su trabajo.

A estos punteros a funciones que se pasan a otro método para que éste indique su finalización, se les conoce
como "Funciones de retorno" (callback functions). Las funciones de retorno son el fundamento de la
invocación asíncrona entre componentes (Web Services y .NET Remoting) en .NET.

Acceso al estado en otros hilos de ejecución


Debido a restricciones de seguridad no es posible acceder de forma directa a las propiedades o variables de
estado de una clase localizada en otro hilo (Thread) de ejecución. Tampoco podemos invocar directamente un
método de una clase localizado en otro hilo. Sin embargo, sí es posible "ejecutar" un puntero a una función
ubicada en otro hilo (lo que equivale en términos sencillos a ejecutar la propia función). Esta particularidad -
que puede parecer una contradicción- se debe al modelo de ejecución del sistema operativo (el cual
abordaremos con más detalle en artículos posteriores).

Métodos anónimos
Los programadores aficionados al paradigma funcional amarán esta funcionalidad incorporada en la reciente
versión del .NET Framework (la 2.0). ¿Porqué? Porque es la antesala de la llegada de las famosas funciones
Lambda omnipresentes y todo poderosas en los lenguajes funcionales a la plataforma .NET.

Un método anónimo en .NET es un método que es definido en aquel lugar en que se le ocupa. Es decir, no
contiene un encabezado, el código de dicho método se incorpora en el lugar en donde debería ir la
invocación a la función. Para lograr lo anterior se utilizan delegados.

Para obtener más detalles sobre esta nueva técnica, puedes acceder a la siguiente página:
http://msdn2.microsoft.com/en-us/vcsharp/default.aspx (al igual que el uso anterior, este tema será tratado en
mayor detalle en artículos posteriores).

Principio de la página

4. Definición e implementación de delegados

La sintaxis para la definición de delegados difiere según el lenguaje. No obstante, los conceptos
fundamentales que se mostrarán a continuación son invariables independientemente del lenguaje que se
utilice:

1. Lo primero que se debe hacer para definir un delegado es indicar cuál será la firma de las funciones a
la que ese delegado podrá apuntar (por firma se entiende el tipo de datos de los parámetros que se
reciben, y el tipo de datos que se retorna):
VB.NET

[Nivel de protección] Delegate [Sub|Function] NombreDelegado (Param1 As [Tipo], Param2


As [Tipo], ...) {As [Tipo
de retorno]}

C#
[Nivel de protección] delegate [Tipo de retorno] NombreDelegado ([Tipo] Param1, Param2
[Tipo], ...)

msdn.microsoft.com/…/bb972282.aspx 2/6
18/06/2010 Delegados en .NET - Parte I

2. El segundo paso consiste en definir las variables que almacenarán los punteros de las funciones que se
invocarán a través del delegado. Para mayor claridad llamaremos a esta variable apuntador. Estas
variables deben ser del tipo de datos del delegado (definido en el paso anterior):
VB.NET

[Nivel de protección] NombreApuntador As [TipoDelegado]

C#
[Nivel de protección] [Tipo Delegado] NombreApuntador

3. Una vez definida la firma del delegado y declarado el apuntador (variable del tipo de delegado) para
invocar las funciones, el tercer paso consiste en indicar cuáles serán esas funciones. Para eso se utiliza
el concepto de "sumar" métodos al apuntador (este concepto queda bastante evidente al observar la
sintaxis para realizar dicha operación en C#):
VB.NET

NombreApuntador = [Delegate].Combine(NombreApuntador, New TipoDelegado(AddressOf Funci


onAAgregar))

VB ofrece una sintaxis un poco más simple en el caso del uso de delegados para manejo
de eventos:
AddHandler NombreApuntador, AddressOf FuncionAAgregar

C#
NombreApuntador += new TipoDelegado(FuncionAAgregar)

4. Ya se puede invocar al apuntador, lo cual provocará la ejecución de todas las funciones que le hayan
sido agregadas. Para invocarlo simplemente basta con hacerlo por su nombre (pasándole los
parámetros requeridos definidos en la firma del delegado).

Principio de la página

5. Ejemplos

Para finalizar este artículo mostraremos dos ejemplos del uso de delegados para la gestión de eventos e
implementación del patrón "Publicador-Suscriptor" (los otros 2 usos mencionados en este artículo se tratarán
con mayor amplitud en posteriores artículos).

Gestión de eventos
En este ejemplo sólo el paso 3 es necesario. La razón de esto es que la variable apuntador para el evento
Click del botón (que de hecho recibe ese mismo nombre) ya se encuentra definida dentro de la clase
System.Windows.Forms.Button provista por el framework de .NET. El delegado al que corresponde dicho
apuntador (que es el mismo para los eventos de todos los controles gráficos) es de tipo
System.EventHandler. Es decir, para la gestión de eventos, lo único que se debe hacer es agregar al
apuntador de cada evento las funciones que serán invocadas cuando éste suceda. (Nota: Algunas secciones
del código han sido suprimidas para facilitar la comprensión del ejemplo):

VB .NET
Partial Class frmDelegados
Inherits System.Windows.Forms.Form

Friend WithEvents btnHolaMundo As System.Windows.Forms.Button

'<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.btnHolaMundo = New System.Windows.Forms.Button
Me.SuspendLayout()
'

msdn.microsoft.com/…/bb972282.aspx 3/6
18/06/2010 Delegados en .NET - Parte I
'btnHolaMundo
'
Me.btnHolaMundo.Location = New System.Drawing.Point(25, 12)
Me.btnHolaMundo.Name = "btnHolaMundo"
Me.btnHolaMundo.Size = New System.Drawing.Size(75, 23)
Me.btnHolaMundo.TabIndex = 0
Me.btnHolaMundo.Text = "Hola mundo"
Me.btnHolaMundo.UseVisualStyleBackColor = True

'inicio paso 3
AddHandler btnHolaMundo.Click, AddressOf ClickBotonHolaMundo
'fin paso 3

End Sub

Private Sub ClickBotonHolaMundo(ByVal sender As Object, ByVal e As EventArgs)


MessageBox.Show(CType(sender, Button).Text)
End Sub

End Class

C#
partial class frmDelegados
{

private System.Windows.Forms.Button btnHolaMundo;

private void InitializeComponent()


{
this.btnHolaMundo = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnHolaMundo
//
this.btnHolaMundo.Location = new System.Drawing.Point(36, 42);
this.btnHolaMundo.Name = "btnHolaMundo";
this.btnHolaMundo.Size = new System.Drawing.Size(93, 28);
this.btnHolaMundo.TabIndex = 0;
this.btnHolaMundo.Text = "Hola mundo";
this.btnHolaMundo.UseVisualStyleBackColor = true;

// inicio paso 3
this.btnHolaMundo.Click += new System.EventHandler(ClickBotonHolaMundo);
// fin paso 3

private void ClickBotonHolaMundo(object sender, EventArgs e) {


MessageBox.Show(((Button)sender).Text);
}
}

Patrón Publicador-Suscriptor

VB .NET

Clase Publicador:
Public Class Publicador
'Paso 1: Definir la firma del evento a publicar
Public Delegate Sub FirmaEventoAPublicar(ByVal texto As String)

'Paso 2: Definir el apuntador para guardar las funciones a invocar


Public EventoAPublicar As FirmaEventoAPublicar

Public Sub OcurrioEvento(ByVal texto As String)

msdn.microsoft.com/…/bb972282.aspx 4/6
18/06/2010 Delegados en .NET - Parte I
'Paso 4: Invocar las funciones agregadas a través del invocador
EventoAPublicar(texto)
End Sub
End Class

Clase Suscriptor:
Public Class Suscriptor

Public Sub AvisemeAqui(ByVal texto As String)


MessageBox.Show("Gracias por avisar. Este es el mensaje recibido:" & texto)
End Sub

End Class

Agregar e invocar los punteros a las funciones:


Private unPublicador As New Publicador
Private unSuscriptor As New Suscriptor
Private otroSuscriptor As New Suscriptor
Private Sub ClickBotonHolaMundo(ByVal sender As Object, ByVal e As EventArgs)
'Paso 3: Agregar los punteros a las funciones a invocar
unPublicador.EventoAPublicar = [Delegate].Combine(unPublicador.EventoAPublicar, New
Publicador.FirmaEventoAPublicar(AddressOf unSuscriptor.AvisemeAqui))
unPublicador.EventoAPublicar = [Delegate].Combine(unPublicador.EventoAPublicar, New
Publicador.FirmaEventoAPublicar(AddressOf otroSuscriptor.AvisemeAqui))
'Llamar al método en el Publicador que invoca a las funciones agregadas al delegado
unPublicador.OcurrioEvento(txtMensaje.Text)
End Sub

C#

Clase Publicador:
class Publicador
{
//Paso 1: Definir la firma del evento a publicar
public delegate void FirmaEventoAPublicar(string texto);

//Paso 2: Definir el apuntador para guardar las direcciones de las funciones a invoc
ar
public FirmaEventoAPublicar EventoAPublicar;

public void OcurrioEvento(string texto)


{
//Paso 4: Invocar las funciones
EventoAPublicar(texto);
}
}

Clase Suscriptor:
class Suscriptor
{
public void AvisemeAqui(string texto)
{
MessageBox.Show("Gracias por avisar. Este es el mensaje recibido:" + texto);
}
}

Agregar e invocar los punteros a las funciones:

msdn.microsoft.com/…/bb972282.aspx 5/6
18/06/2010 Delegados en .NET - Parte I
private Publicador unPublicador = new Publicador();
private Suscriptor unSuscriptor = new Suscriptor();
private Suscriptor otroSuscriptor = new Suscriptor();

private void ClickBotonHolaMundo(object sender, EventArgs e)


{
//Paso 3: Agregar los punteros a las funciones a invocar
unPublicador.EventoAPublicar += new
ublicador.FirmaEventoAPublicar(unSuscriptor.AvisemeAqui);
unPublicador.EventoAPublicar += new
ublicador.FirmaEventoAPublicar(otroSuscriptor.AvisemeAqui);
//Llamar al método en el Publicador que invoca a las funciones agregadas al dele
gado
unPublicador.OcurrioEvento(txtMensaje.Text);
}

Johann Granados se desempeña como consultor y es MVP en .NET Compact Framework.

Principio de la página

Administre su perfil | MSDN Flash en Español | Contacto | Aviso legal


© 2010 Microsoft Corporation. Reservados todos los derechos. Términos de uso | Marcas
Registradas | Privacidad | Comentarios

msdn.microsoft.com/…/bb972282.aspx 6/6

Vous aimerez peut-être aussi