martes, 29 de abril de 2014

Métodos, Delegados Anónimos



Lo primero para ver este apartado es explicar que podemos encontrárnoslo como Métodos Anónimos o Delegados Anónimos, aunque también podemos referirnos a ellos como Funciones Anónimas, o Funciones o Métodos ‘Inline’. Aparecieron en la versión 2.0 del Framework y vinieron a cubrir la incapacidad de poder definir un método dentro de cualquier porción de código, sin tener que echar mano de la forma clásica [public/private void/int/string/ … nombreMétodo (parámetros)].


Esto como veremos en la siguiente entrega fue superado por creces con la introducción de la Expressiones Lambda en la versión del Framework 3.0 y con el concepto de Inferencia de Tipos, pero como veremos en esta hay una excepción que poseen los delegados anónimos que no pueden realizar las Expressiones Lambda.



Recuerda que aquí tienes el indice de todos los posts del Curso de LinQ.


El concepto de método anónimo es un concepto muy sencillo, y consiste en la capacidad de poder declarar dentro de un método otro método o bloque de código, sin necesidad de realizar una declaración formal. La declaración de este nuevo método tendrá la obligación de ser almacenada dentro de un delgado o un evento.

Vamos a ver un ejemplo con un delegado.

Declaramos el delegado:

public delegate string MiDelegado(string mensaje);

Declaramos un método que cumpla con la firma de nuestro delegado, por ejemple este:

public static string AñadirFechaAMensaje(string mensaje)
{
    return string.Format("{0} - {1}", mensaje, DateTime.Now);
}

Un método que simplemente recibe un mensaje y le añada la fecha.


Ahora vamos a instanciar el delegado con el uso de este método, como haríamos de forma tradicional:

static void Main(string[] args)
{
    MiDelegado miDelegado = new MiDelegado(AñadirFechaAMensaje);
}

Utilizando los métodos anónimos podríamos haber escrito el mismo código sin necesidad de crear un método independiente, para ello utilizaremos la palabra reservada delegate, más una lista de parámetros (en caso de que los necesite) y la apertura y cierre de llaves ({}) finalizando con el punto y coma de cierre de línea.

Este sería el resultado:

static void Main(string[] args)
{
    //MiDelegado miDelegado = new MiDelegado(AñadirFechaAMensaje);
 
    MiDelegado miDelegado = delegate(string mensaje)
    {
        return string.Format("{0} - {1}", mensaje, DateTime.Now);
    };
}

Vamos a ver un ejemplo con eventos, y para ello vamos a intentar hacerlo de la forma más clásica con una app muy sencillita de Windows Forms:














Ahora nos vamos a suscribir a su evento Click, pero no utilizando la forma que nos ofrece Visual Studio mediante doble click sobre el button en tiempo de diseño, o mediante la ventana de propiedades, lo vamos a hacer dentro de su constructor:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
 
        this.button1.Click += button1_Click;
    }
 
    void button1_Click(object sender, EventArgs e)
    {
        Button b = (Button) sender;
 
        MessageBox.Show(string.Format("Hemos apretado el botón {0}", b.Name));
    }
}

Para hacer esto simplemente hemos escrito el nombre del botón con su evento Click y el ‘+=’ dando dos veces al ‘tab’ y Visual Studio se ha encargado de añadirnos el método independiente para firma de nuestro delegado asociado al evento Click de la clase Button, el EventHandler. Esto concuerda exactamente con el ejemplo que hemos hecho en el paso anterior, así que como hicimos en este ahora vamos a reducirlo eliminando el método independiente y haciendo su instanciación en línea.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
 
        this.button1.Click += delegate(object sender, EventArgs e)
        {
            Button b = (Button) sender;
 
            MessageBox.Show(string.Format("Hemos apretado el botón {0}", b.Name));
        };
    }
 
}


*** Al principio de la entrada indicábamos que los métodos anónimos tienen una capacidad que poseen las Expresiones Lambda y es que en caso de no hacer uso de los parámetros, estos pueden ser obviados en la declaración, reduciendo el código escrito. En el ejemplo anterior, si en nuestro mensaje solo quisiéramos decir que se ha apretado un botón, podríamos reducir así el código:


public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
 
        this.button1.Click += delegate{ MessageBox.Show("Hemos apretado el botón"); };
    }
 
}


La utilización de métodos anónimos conlleva una serie de mejoras a la hora del ahorro de tener que crear sobrecargas de métodos innecesarios, y a la comprensión del código, ya que la funcionalidad del método está presente en la declaración del mismo delegado/evento.


El uso de métodos anónimos tiene una serie de restricciones, y son las siguientes:

  • El ámbito de un método anónimo es el bloque del código del mismo.
  • No se deben utilizar instrucciones de salto, tales como goto, break o continue en un bloque de un método anónimo si el destino está fuera del mismo.
  • Un método anónimo no puede tener acceso a parámetros ref o out.