10 de noviembre de 2009

C# Delegado

Veamos un ejemplo práctico y sencillo del uso de eventos delegados, de forma que nos quede claro su concepto y su uso.

¿Que es un Delegado?

Un delegado (delegate) es un tipo especial de clase cuyos objetos pueden almacenar referencias (punteros, apuntadores) a uno o más métodos, posibilitándonos (desde el objeto) lanzar la ejecución en cadena de todos estos métodos.

Hasta aquí la definición mas sencilla posible, pero igualmente algo complicada de entender, expliquémosla a través de 2 ejemplos abstractos con la esperanza de que se comprenda algo mejor:

 

Delegado Ejemplo Simple

Por ejemplo, si queremos "interceptar” el evento Click de un botón llamado btnPrueba1 y asociarlo a un determinado método que ya tuviéramos definido (MetodoPruebaDelegado), tendremos que:

  • Definir el método (MetodoPruebaDelegado) de forma que tenga la misma firma que el delegado asociado a ese evento.
protected void MetodoPruebaDelegado(object sender, EventArgs e)
{
  //Aquí escribiríamos el código que quisiéramos ejecutar en dicho evento…
}
  • Lo próximo sería asociar el método creado (MetodoPruebaDelegado) con el evento Click del botón. Para lograrlo podremos usar cualquiera de las dos formas que veremos a continuación, usando la forma tradicional o la que se incluyó en la versión 2.0 del lenguaje (covarianza):
// Asignación del método del evento usando el constructor del delegado
this.btnPrueba1.Click += new System.EventHandler(this.MetodoPruebaDelegado);
 
// Asignación del método usando la covarianza
this.btnPrueba1.Click += this.MetodoPruebaDelegado;
 
Nota:
Hasta aquí hemos visto como asociar un método (MetodoPruebaDelegado) al evento (Click) de un control (btnPrueba1), no hemos hablado nada de los DELEGADOS; pero en C# eventos y delegados están muy ligados como veremos a continuación. De hecho no se puede definir un evento si no definimos previamente un delegado.

 

Delegado Ejemplo Práctico

Si tuviéramos una página Page1 y un control de usuario uc1, y quisiéramos desde un método de uc1 llamar a un método de Page1, tendríamos que declarar un delegado en uc1 y desde Page1 almacenar en el delegado el método de la página (uc1.Delegado1 = Page1.Método).

Creo que igual me enrede, en fin veamos un caso práctico y concreto que recientemente tuve, donde usé un delegado (delegate).

Imaginemos la siguiente problemática: Tengo que implementar una búsqueda de vuelos aéreos (ver imagen):

Delegado, Buscador de Vuelo

Para ello crearemos una página que contendrá, entre otras cosas, 2 controles y un método:

  • ucBuscadorCriterios (marcada en rojo): Contiene las condiciones de filtros a establecer para la búsqueda del vuelo.
  • ucBuscadorResultado (marcada en azul): Contendrá los resultados de los vuelos que cumplen las condiciones establecidas.
  • BuscarVuelos(): Método que se encargará de buscar y devolver todos los vuelos que cumplen con unas ciertos criterios de búsqueda. Los criterios son definidos en ucBuscadorCriterios y los resultados los usaremos para mostrarlos en ucBuscadorResultado.

Hasta aquí todo bien, pero si nos fijamos en ucBuscadorCriterios (rojo) dentro tiene el botón btnBuscarVuelos, el cual debe lanzar la búsqueda, o sea, debe llamar al método BuscarVuelos() que está en la página. Nuestro problema sería:

¿Como llamar a Page1.BuscarVuelos() desde Page1.ucBuscadorCriterios?

La respuesta es sencilla, usaremos un delegado (delegate).

Usando Delegado (Delegate)

  1. Lo primero que haremos es declarar el delegado (MyDelegadoBuscarEventHandler), este delegado contiene o define la “firma” del evento, en nuestro ejemplo debemos abrir el código del control de usuario (ucBuscadorCriterios) y definir nuestro delegado.
  2. Después definimos el evento (AereoBuscadorBuscarClick) que será del tipo delegado (MyDelegadoBuscarEventHandler), hasta aquí si retiramos las palabras “public event” podríamos leer como que hemos declarado una “variable especial” del tipo del delegado.
  3. Posteriormente en el evento asociado al clic del botón “Buscar Vuelos” (AereoBuscadorBuscar_Click) haremos la llamada al evento (AereoBuscadorBuscarClick). Aquí debemos tener en cuenta que antes de hacer la llamada al evento debemos chequear que dicho evento tiene a alguien suscrito (AereoBuscadorBuscarClick != null).
  4. Ya lo tenemos casi todo hecho solo nos falta asociar (suscribir) el método que nos interesa Page1.BuscarVuelos() al evento (AereoBuscadorBuscarClick).
public partial class UserControlsAereoBuscadorCriterios : UserControl
{
  //Declarar el delegado
  //(puntero a la función que se encuentra en la pagina)
  public delegate void MyDelegadoBuscarEventHandler();
  public event MyDelegadoBuscarEventHandler AereoBuscadorBuscarClick;
 
  protected void Page_Load(object sender, EventArgs e) {}
 
  //Evento asociado al botón AereoBuscadorBuscar y que es un delegado o puntero 
    a la función que se encuentra en la pagina
  protected void AereoBuscadorBuscar_Click(object sender, EventArgs e)
  {
    if (AereoBuscadorBuscarClick == null) return;
   
    AereoBuscadorBuscarClick();
  }
}
Para asociar el evento que hemos creado (AereoBuscadorBuscarClick) al método de la página (Page1.BuscarVuelos()) tenemos que ir al código de la página y en el evento Page_load hacer la asociación correspondiente:

protected void Page_Load(object sender, EventArgs e)
{
   //Asociar el delegado del control de usuario
   ucBuscadorCriterios.AereoBuscadorBuscarClick += BuscarVuelos;
}
internal void BuscarVuelos() {}

Y todo listo, ya tenemos un ejemplo práctico de un delegado (delegate)…

Después de escribir el artículo no se si ha quedado clara la idea de uso de un delegado. Por eso resumiré algunos puntos por si queda alguna duda:

Resumen:

Siempre que queramos hacer uso de los eventos y delegados en C# deberemos:

  1. Declarar el delegado. Para el mejor entendimiento debemos tener en cuenta que el delegado no es otra cosa que una “clase (tipo de dato) especial”.
  2. Declarar el evento de tipo del delegado. Si tenemos en cuenta que el delegado es una clase, pues el evento es algo como una “propiedad especial” del tipo delegado.
  3. Implementar el método X a suscribir. Este método deberá tener la misma “firma” que el delegado.
  4. Por ultimo, para asociar o enlazar un método X al evento, accedemos a la propiedad del objeto y le “adicionamos” el método. Teniendo en cuenta que el método X tiene que cumplir con la firma del delegado.

 

Artículos Relacionados: