jueves, 16 de julio de 2009

Delegados en C#

Un delegado es un tipo que especifica un método a llamar, y opcionalmente una referencia a otro delegado. Normalmente se utilizan, aparte de otras cosas, para implementar callbacks y eventos. Entonces, en pocas palabras para los programadores de C++, podemos decir que un delegado es un puntero a un método.

 

Además, los delegados en .net permiten la ejecución asíncrona del método apuntado (Ver),  y también nos permiten obtener un arreglo de los delegados que está apuntando en cadena.

 

¿Cómo declaro un delegado?

 

Supongamos que tenemos el siguiente método:

 

public int Sum(int a, int b)

{

     return a + b;

}

 

Entonces para crear un delegado tenemos que respetar tu firma y su tipo de retorno, quedaría así:

 

public delegate int SumDelegate(int a, int b);

 

Es practicamente un método pero sin cuerpo y con la palabra DELEGATE antes del tipo de retorno. Veamos un ejemplo de uso:

 

public void main(string[] args)

{

     // instanciamos y apuntamos al método Sum.

     SumDelegate sd = new SumDelegate(Sum); 

     //llamamos al delegado y como éste está apuntando

      //a Sum, lo ejectuta y retorna el resultado.

     int result = sd(2,3); // result es igual a 5

}

 

Ahora veamos un uso importante de los delegados:

Los eventos

Un evento es una acción que se inicia fuera de contexto, es manejado en uno más  métodos del programa. Por ejemplo un evento iniciado por el usuario sería el Mouse Click, pero también hay eventos que son iniciados por otros objetos por ejemplo: Application.ThreadException para manejar las excepciones de la aplicación.

Algo que hay que tener en cuenta es que un evento es un delegado que nada más puede invocarse desde el contexto en donde se declaró. Esto quiere decir que una clase que tenga un evento, éste solamente puede llamarse desde dentro de la clase y no fuera de ésta.

Otra punto importante es que el delegado que usemos para definir el evento puede ser cualquiera, tanto uno que venga en el framework como otro nuestro.

Ejemplo:

//esta es la clase donde está el evento

public class Person

{

     //Definimos el evento usando el Delegado EventHandler

     //EventHandler es un delegado bastante usado para eventos que

     //no necesiten pasar datos hacia los parámetros del método suscrito

     public event EventHandler NameChanged;

     public string m_name;

     public string Name

     {

          get { return m_name; }

          set

          {

                //Si el nombre cambia:

                if(value != name)

               {               

                   m_name = value;

                   //Si no hay suscripciones a NameChanged éste queda null

                   //entonces si no es null podemos invocarlo.

                   if(NameChanged != null)

                       NameChanged(this, EventArgs.Empty);

                 }

           }

     }

}

 

//esta es la clase donde está suscrito el evento

public class TestClass

{

     public void Test()

     {

          Person p = new Person();

          p. Name =”Pepe”;   // no se ejecuta el evento

          p.NameChanged += new EventHandler(Person_NameChanged);

          p.Name = “Juan”; // ya estamos suscritos y se ejecuta el NameChanged

      }

      prívate void Person_NameChanged(object sender, EventArgs e)

      {

          //Aki hacemos algo cuando cambie el nombre de person.

      }

}

Siempre hay que mantener el uso del sender y el argumento.  En caso de que se quiera pasar data, simplemente en vez de colocar EventArgs, se coloca una clase que herede de ésta y se le ponen las propiedades necesarias.

Ejml:

public class NameChangedEventArgs : EventArgs

{

       private string m_newName;

       public string NewName

       {

               get { return m_newName; }

       }

}


Ahora quedan dos formas de utilizarlo, la primera es crear nuestro delegado y la segunda es utilizar al EventHandler genérico el cual vamos a hablarles en otra ocasión. Entonces vamos a definir nuestro delegado:

public delegate void NameChangedEventHandler(object sender, NameChangedEventArgs e);

El uso es idéntico al ejemplo anterior pero cambiamos EventHandler por NameChangedEventHandler.


Gracias por leer!

1 comentario: