miércoles, 29 de agosto de 2007

Introducción a las pruebas unitarias ó Unit Test en C#

En esta ocasión vamos a introducirnos a un concepto que está en boca de todo desde hace un tiempo, las pruebas unitarios, que según algunos son la solución a todos los problemas del desarrollo de software y su complejidad inherente. Pues bien, esto no es tan así, porque si bien las pruebas unitarias nos permiten asegurar que nuestros artefactos pasan las pruebas, ésta últimas deben cubrir los casos correspondientes y esto depende de quien las ha escrito. Pero bueno dejemos la discusión para más adelante, vamos a ver de qué se trata.

Divide y triunfarás

Esta frase de Máxima Maquiavelo tiene mucho de cierto, si algo es muy complejo para enfrentarlo, sobre todo si es a causa de su tamaño, es mejor dividirlo en partes pequeñas; por lo tanto si tenemos un sistema de información complejo es natural que lo descompongamos, en nuestro caso en clases y métodos. Las pruebas unitarias se basan en esto como idea principal, antes que nada nuestras mentes no pueden manipular más de siete ideas simultáneamente (seguramente la mia un poco menos que eso), por lo tanto un sistema complejo es demasíado para comprenderlo completo, es por esto que se separa en partes para poder comprender cada una individualmente. Las pruebas unitarias apuntar a probar estas partes.

Entonces, ¿Cómo que es exáctamente una prueba unitaria?

En software una prueba unitaria no es más que una clase con algún método que permite probar otro método, para evaluar el resultado se utilizan asserts (afirmaciones), del siguiente modo: sabemos que el método Pow de la clase Math nos dará como resultado "a" elevado a "b", bien para probarlo hacemos

Assert.AreEqual(Math.Pow(2,3),8);

En este caso estamos diciendo que la prueba unitaria nos indique si el resultado de Math.Pow(2,3) es igual a 8, en caso de no serlo la prueba unitaria no será exitosa.

Primer ejemplo de código con VSTS

Vamos a ver cómo quedaría una clase para probar esto con VSTS

namespace TestProject1 
{ 
 [TestClass()] 
 public class ProgramTest 
 { 
  [TestMethod()] 
  public void SumarTest() 
  { 
   Assert.AreEqual(8, Math.Pow(2, 3)); 
  } 
 } 
}

Lo único particular de este código es que la clase se encuentra adornada con el atributo TestClass y el método de prueba con TestMethod, dentro del método la línea que realiza la prueba, para probar esto con VSTS es necesario invocar al TestManager

 

 

Corremos la prueba de unidad y vemos que funciona, desde el resultado.

 

 

Ok, esto es muy tonto, sin embargo eficiente, si cambiaramos la implementación de Math.Pow podríamos decir que sigue siendo válida porque pasa esta prueba de unidad, por lo tanto cumple con su cometido, vamos a ver un ejemplo más real.

Eficiencia de las pruebas unitarías

Las pruebas unitarías no son la panacea, ni mucho menos, porque dependen de quién las escribe, vamos a desarrollar un ejemplo completo y demostrar por qué es importante que las pruebas sean correctas y consideren la mayor cantidad de cosas posibles.

Supongamos que necesitamos crear un método que toma dos parámetros numéricos y nos devuelve la suma, bien si escucharon alguna vez acerca de programación comandada por pruebas (TDD) se preguntarás qué es esto, bien, justamente, descomponemos nuestro sistema en partes para finalmente tener operaciones lo más atómicas posibles para una primera aproximación y antes de escribir nada de código las probamos. Pero cómo se hace esto, bien veamos nuestro ejemplo de la operación de suma.

Primero definimos la interfase del método

Como dice el título definimos la interfase del método, no debería ser difícil ya que se desprende de nuestro análisis anterior, hagamos el nuestro.

public int Sumar(int a, int b)
{
 return 0;
}

Bien, tenemos nuestro método sin emplementación ahora sin hacer nada, vamos a la prueba unitaria, nuevamente hacemos botón derecho sobre el método y VSTS nos propone crear la prueba, aceptamos y vemos el código generado

[TestMethod()] 
public void SumarTest() 
{ 
 Program target = new Program(); // TODO: Initialize to an appropriate value 
 int a = 0; // TODO: Initialize to an appropriate value 
 int b = 0; // TODO: Initialize to an appropriate value 
 int expected = 0; // TODO: Initialize to an appropriate value 
 int actual; actual = target.Sumar(a, b); 
 Assert.AreEqual(expected, actual); 
}

Bien, a esto tenemos que configurarlo para que la prueba sea útil tenemos que poner valores en a, b, expected, pongamos 2,3 y 5 sucesivamente.

[TestMethod()] 
public void SumarTest() 
{ 
 Program target = new Program(); 
 int a = 2; 
 int b = 3; 
 int expected = 5; 
 int actual; actual = target.Sumar(a, b); 
 Assert.AreEqual(expected, actual); 
}

Lo corremos y listo, no funciona, nos da error, obviamente porque no implementamos el método, con esto por ejemplo podemos pasarlo a un desarrollador para que implemente el método, pero no seamos tan pacatos, hagámoslo nosotros

public int Sumar(int a, int b) 
{ 
 return a + b; 
}

Sencillo, y corremos el test y pasa con éxito.

Bueno, ahora sabemos qué es el desarrollo guiado por pruebas, pero...(siempre hay un pero) nuestra prueba no es del todo eficiente, por ejemplo hagamos lo siguiente en la prueba de unidad.

Imaginemos que le damos la prueba de unidad al programador y nos devuelve el código que pasa la prueba, buenísimo, pero se nos ocurre probar los siguiente

[TestMethod()] 
public void SumarTest() 
{ 
 Program target = new Program(); 
 int a = 6; 
 int b = 3; 
 int expected = 9; 
 int actual; 
 actual = target.Sumar(a, b); 
 Assert.AreEqual(expected, actual); 
}

No pasa, vamos al código de método y vemos esto:

public int Sumar(int a, int b) 
{ 
 return 5; 
}

Caramba, algo falló y no fué el programador, el test estaba mal planteado, como regla deberíamos considerar un par de casos de éxito y por qué no, de error, de este modo

        [TestMethod()]
        public void SumarTest()
        {
            Program target = new Program(); 
            int a = 6;
            int b = 3;
            int expected = 9;
            int actual;
            actual = target.Sumar(a, b);
            Assert.AreEqual(expected, actual);
 
            a = 2;
            b = 3;
            expected = 5;
            actual = target.Sumar(a, b);
            Assert.AreEqual(expected, actual);
 
            a = 6;
            b = 3;
            expected = 8;
            actual = target.Sumar(a, b);
            Assert.AreNotEqual(expected, actual);
 
            a = 2;
            b = 3;
            expected = 9;
            actual = target.Sumar(a, b);
            Assert.AreNotEqual(expected, actual);
        }

Con esta prueba de unidad nos aseguramos un par de casos de éxito y de error, se puede considerar correcta para lo que necesitamos.

Conclusión

Las pruebas unitarias son de mucha ayuda, permiten detectar problemas de diseño, nos ayudan a hacer código más atómico, a tener componentes probados antes de la integración, pero es necesario detenerse a pensarlas un momento para que sean correctas. Saludos.

lunes, 20 de agosto de 2007

¿Cómo se utilizan los eventos en .net?

En un post anterior hablaba acerca de los delegados y su función, por si no lo leyeron o no lo recuerda (o no les intersa leerlo) lo resumo en pocas palabras. Los delegados son el mecanísmo por el cual indicamos cómo debe ser un método para poder interactuar con un evento o con un método que acepte un método como parámetro. Dicho más claro, podemos utilizar un método como parámetro de otro método, para indicar cómo debe ser el método parámetro utilizamos un delegado. Para los eventos es lo mismo, podemos asociar métodos a un evento, para indicar cómo deben ser los métodos utilizamos delagados.

¿Qué es un evento?

Un evento es un suceso, en .net es la acción de invocar un método de una clase cliente sin conocer cuál es este método. Por ejemplo un objeto B lanza su evento E1, ya que E1 fue asociado a el método M1 del objeto A este método es disparado al disparar el evento, sin que el objeto B lo sepa.

¿Cómo lo hacemos?

Bien, si nosotros desde nuestra clase servidor necesitamos informar a una clase cliente que algo ocurrió pero no conocemos a la clase cliente lo que hacemos es crear un evento. Un evento se utiliza asociado a un delegado, definimos un delegado que indica cómo debe ser el método que vamos a invocar y luego el evento que lo utiliza, a partir de esto la clase cliente puede asociar cualquier método que cumpla con el delegado al evento, para que nosotros desde la clase servidor disparemos el eventos y éste llame al método, pero sin saber a qué metodo llama, es más, puede llamar a múltiples métodos de múltiples clases sin saberlo, pero basta de charla veamos un ejemplo.

Primer ejemplo

Un caso típico de la utlización de eventos son los Winform, es éstos los eventos se utlizan para que un objeto, por ejemplo un botón, informe al formulario que ha sido pulsado, hagamos la siguiente prueba, creemos un proyecto Winform y agregemos un botón el formulario que aparece por defecto.

Si hacemos doble click sobre el botón el IDE nos envía al código.

   1:  private void button1_Click(object sender, EventArgs e) 
   2:  {
   3:  }

Aunque pocas veces nos detenemos a pensarlo, este método se genera automáticamente y es asociado al evento Click del botón sin que nos enteremos, abramos el archivo Form1.Designer.cs Si vamos al método InitilizeComponent vemos el siguiente código

   1:  // button1 
   2:  // this.button1.Location = new System.Drawing.Point(24, 28); 
   3:  this.button1.Name = "button1"; 
   4:  this.button1.Size = new System.Drawing.Size(75, 23); 
   5:  this.button1.TabIndex = 0; 
   6:  this.button1.Text = "button1"; 
   7:  this.button1.UseVisualStyleBackColor = true; 
   8:  this.button1.Click += new System.EventHandler(this.button1_Click); 
   9:  // // Form1 // 

La línea donde se encuentra la mágia es esta
this.button1.Click += new System.EventHandler(this.button1_Click);

Esto nos dice que el objeto button1 tiene su evento Click asociado el método button1_Click, ahora ¿qué significa System.EventHandler?, los más suspicaces adivinan que se trata de un delegado y es verdad, si nos ponemos sobre el código y presionamos F12 vemos la definición

public delegate void EventHandler(object sender, EventArgs e);

Es un delegado, en el cual se define que los métodos que lo utilicen debe devolver void y recibir dos parámetros. Hasta ahora es muy claro, se define un delegado con una firma tal y se asocia un método que cumpla con dicho delegado al evento, perfecto, pero cómo se declara el evento?.

Declarando un evento

Ponemos el cursos sobre Click y presionamos F12, saltamos al código de la clase Component (porque un botón hereda de ella) y vemos el siguiente código
public event EventHandler Click

Es la definición del evento, noten que después de la palabra event se define qué delegado se utliza, para poder asociar el evento a cualquier método que cumpla con el mismo, por último el nombre del evento, en este caso Click.

Asociando más métodos a los eventos

Por lo tanto podemos asociar cualquier método que cumpla con el delegado al evento, es cierto, hagamos la prueba, definamos un evento del siguiente modo

   1:  private void Form1_Load(object sender, EventArgs e) 
   2:  { 
   3:    this.button1.Click += MiMetodo; 
   4:  } 
   5:  private void MiMetodo(object sender, EventArgs e) 
   6:  { 
   7:    MessageBox.Show("Evento generado por " + sender.ToString()); 
   8:  }

Nuestro método "MiMetodo" cumple con el delegado EventHandler y dentro simplemente muestra un mensaje. en la línea this.button1.Click += MiMetodo asociamos el método al evento, noten que no creamos un objeto EventHandler, no es necesario gracias a la inferencia de tipos, es decir, el compilador nos ahorra el trabajo de hacerlo porque comprueba que nuestro método cumple con el delegado esperado, se puede hacer de cualquiera de las dos formas, es cuestión de gustos.

Si lo corremos vemos lo siguiente

Mágico, se ejecutó nuestro método, y también se ejecuto Button1_OnClick, y se ejecutarán todos los que se encuentren asociados, es más un método puede encontrarse asociado a múltiples eventos y un evento a múltiples métodos.

Un ejemplo desde cero

Hagamos un ejemplo desde cero para cerrar el concepto Supongamos que queremos que un formulario A al presionar un botón abra un formulario B, este formulario B tiene un botón que al presionarlo escribe un texto en un textbox del formulario A. ¿Cómo lo hacemos?. Primero que nada identifiquemos quién es de los dos el que dispara el evento y quién recibe el evento. Evidentemente si desde el formulario B necesitamos que ocurra algo en el A es claro que el formulario B llama al A a través de un evento, por lo tanto el evento debe encontrarse definido en el formulario B y el método que se asocia al evento en el A. Perfecto, hay algo más, necesitamos que cuando B llame al método de A le pase un texto para que se imprima, entonces el delegado tiene que tener un parámetro, para que el método reciba el texto.

Definiendo el delegado

Como dije antes necesitamos pasarle al método un texto, por lo tanto debe recibir un parámetro del tipo string y no regresar nada, entonces creamos otro formulario y agregamos el siguiente código:

   1:      public partial class Form2 : Form
   2:      {
   3:          public delegate void DelegadoMensaje(string mensaje);
   4:          public event DelegadoMensaje MiEvento;
   5:   
   6:          private void button1_Click(object sender, EventArgs e)
   7:          {
   8:              this.MiEvento("Hola evento con parámetros!!!");
   9:          }
  10:   
  11:          public Form2()
  12:          {
  13:              InitializeComponent();
  14:          }
  15:   
  16:          private void Form2_Load(object sender, EventArgs e)
  17:          {
  18:   
  19:          }
  20:   
  21:      }

Vamos paso a paso, en la línea 3 definimos el delegado para indicar cómo deben ser los métodos que se asocien al eventos, en este caso serán métodos que reciban un texto como parámetro y no retornen nada. En la línea 4 definimos el evento utilizando el delegado. Luego en la línea 8 dentro del evento que dispara el botón llamamos al evento y le pasamos un texto, en este momento se invocarán todos los métodos que hayan sido asociados a él.

Falta llamar desde el Form1 al Form2 y asociar un método al evento del Form2. Hagámoslo.

   1:      public partial class Form1 : Form
   2:      {
   3:          Form2 form2 = new Form2();
   4:   
   5:          public Form1()
   6:          {
   7:              InitializeComponent();
   8:          }
   9:   
  10:          private void button1_Click(object sender, EventArgs e)
  11:          {
  12:              form2.Show();
  13:          }
  14:   
  15:          private void Form1_Load(object sender, EventArgs e)
  16:          {
  17:              //this.button1.Click += MiMetodo;
  18:              form2.MiEvento += new Form2.DelegadoMensaje(form2_MiEvento);
  19:          }
  20:   
  21:          void form2_MiEvento(string mensaje)
  22:          {
  23:              this.label1.Text = mensaje;
  24:          }
  25:   
  26:          private void MiMetodo(object sender, EventArgs e)
  27:          {
  28:              MessageBox.Show("Evento generado por " + sender.ToString());
  29:          }
  30:   
  31:      }

En la línea 3 creamos un objeto del tipo Form2, en la línea 18 asociamos el método form2_MiEvento al evento, y luego en la línea 23 actualizamos el valor de la etiqueta, por lo tanto, el método form2_MiEvento va a ser invocado desde el Form2 cuando se presione el botón. Vamos a probarlo.

Funciona, perfecto, esto es sólo una introducción, hay muchas cosas interesantes acerca de los eventos, se pueden utilizar en aplicaciones de consola, en ASP.NET. Nos vemos en la próxima.

[HUMOR] Dilbert: Salarios

sábado, 11 de agosto de 2007

[VIDEO] Introducción a delegados en .net

Dejo un video con una introducción teórica y un ejemplo de delegados en .net.

miércoles, 8 de agosto de 2007

Llegó el Flight Simulator

Finalmente después de dos meses de conseguir la cuarta estrella en el concurso desarrollador cinco estrellas tengo entre mis manos mi copia del Flight Simulator X Deluxe. Gracias a la gente de Microsoft, es la primera vez que tengo un Flight Simulator.

martes, 7 de agosto de 2007

Patrones creacionales.

Con este soberbio título comenzamos una series post que hace tiempo que tengo en el tintero.

Introducción

Los patrones creacionales son modos de crear objetos siguiendo ciertas reglas según el escenario que nos aseguran un comportamiento esperable. O sea, si lo hacemos así sabemos lo que vamos a obtener.

Creando Objetos

El modo básico de crear un objeto es el siguiente
Persona persona = new Persona().

Muy bien, esto es correcto, pero qué pasa si nuestra clase Persona necesita, al ser creada, un parámetro. Entonces hacemos esto

Persona persona = new Persona(“Leonardo”);
En este caso la clase Persona recibe un parámetro del tipo String que permite indicar el nombre de la persona, perfecto. Imaginemos que con ese nombre accedemos a una base de datos y recuperamos el resto de los datos de la persona… ¿cómo se resuelve?


   1:  public class Persona
   2:  {
   3:      private int _edad;
   4:      private string _nombre;
   5:      private string _apellido;
   6:      private DateTime _fechaNacimiento;
   7:   
   8:      public DateTime FechaNacimiento
   9:      {
  10:          get { return _fechaNacimiento; }
  11:          set { _fechaNacimiento = value; }
  12:      }
  13:   
  14:      public string Apellido
  15:      {
  16:          get { return _apellido; }
  17:          set { _apellido = value; }
  18:      }
  19:   
  20:      public string Nombre
  21:      {
  22:          get { return _nombre; }
  23:          set { _nombre = value; }
  24:      }
  25:   
  26:      public int Edad
  27:      {
  28:          get { return _edad; }
  29:          set { _edad = value; }
  30:      }
  31:   
  32:      public Persona() { }
  33:   
  34:      public Persona(string nombre)
  35:      {
  36:          string connectionString = ConfigurationManager.ConnectionStrings["local"].ConnectionString;
  37:          string sql = "SELECT Edad, Apellido, FechaNacimiento FROM Persona where Nombre='" + nombre + "'";
  38:   
  39:          using (SqlConnection connection = new SqlConnection(connectionString))
  40:          {
  41:              connection.Open();
  42:              SqlCommand cmd = new SqlCommand(sql, connection);
  43:   
  44:              using (SqlDataReader reader = cmd.ExecuteReader())
  45:              {
  46:                  while (reader.NextResult())
  47:                  {
  48:                      this.Apellido = (string) reader["Apellido"];
  49:                      this.FechaNacimiento= Convert.ToDateTime(reader["FechaNacimiento"]);
  50:                      this.Edad = (int)reader["Edad"];
  51:                  }
  52:                  reader.Close();
  53:              }
  54:              connection.Close();
  55:          }
  56:      }
  57:  }

Más allá de que no es el código ideal, es un lugar muuuuyyyy feo para ponerlo, ¿o no?, para quienes duden la respuesta es sí, es un lugar muy feo para esto, nuestra clase Persona no tiene que saber que hay un connectionString que hay una base de datos, un archivo de configuración, nada de eso. Vamos a ver cómo mejorarlo.

Primer acercamiento, Factory Method

Un segundo problema de esta implementación es que aún se pueden crear objetos de la clase Persona sin asignar nada porque tenemos el constructor definido y accesible, la solución es poner el constructor sin parámetros privado, quitar el segundo constructor y crear un método dentro de la clase que tenga todo ese código de inicialización, acepte el parámetro nombre y devuelva un objeto Persona, por supuesto que debe ser estático para poder accederlo, veámoslo.


   1:  public class Persona
   2:  {
   3:      private int _edad;
   4:      private string _nombre;
   5:      private string _apellido;
   6:      private DateTime _fechaNacimiento;
   7:   
   8:      public DateTime FechaNacimiento
   9:      {
  10:          get { return _fechaNacimiento; }
  11:          set { _fechaNacimiento = value; }
  12:      }
  13:   
  14:      public string Apellido
  15:      {
  16:          get { return _apellido; }
  17:          set { _apellido = value; }
  18:      }
  19:   
  20:      public string Nombre
  21:      {
  22:          get { return _nombre; }
  23:          set { _nombre = value; }
  24:      }
  25:   
  26:      public int Edad
  27:      {
  28:          get { return _edad; }
  29:          set { _edad = value; }
  30:      }
  31:   
  32:      public Persona() { }
  33:   
  34:      public static Persona Create(string nombre)
  35:      {
  36:          Persona2 persona = new Persona2();
  37:   
  38:          string connectionString = ConfigurationManager.ConnectionStrings["local"].ConnectionString;
  39:          string sql = "SELECT Edad, Apellido, FechaNacimiento FROM Persona where Nombre='" + nombre + "'";
  40:   
  41:          using (SqlConnection connection = new SqlConnection(connectionString))
  42:          {
  43:              connection.Open();
  44:              SqlCommand cmd = new SqlCommand(sql, connection);
  45:   
  46:              using (SqlDataReader reader = cmd.ExecuteReader())
  47:              {
  48:                  while (reader.NextResult())
  49:                  {
  50:                      persona.Apellido = (string)reader["Apellido"];
  51:                      persona.FechaNacimiento = Convert.ToDateTime(reader["FechaNacimiento"]);
  52:                      persona.Edad = (int)reader["Edad"];
  53:                  }
  54:                  reader.Close();
  55:              }
  56:              connection.Close();
  57:          }
  58:          return persona;
  59:      }
  60:  }

Mejor, esto se conoce como Factory Method, en una implementación más sólida pondríamos el factory method en otra clase la cual será la encargada de crear Personas, y la llamaremos PersonaFactory, con esto quitamos toda la responsabilidad a la clase Persona de hacer cosas que no debe, un detalle más es que la clase Persona debería tener el constructor internal para que lo pueda ver PersonaFactory dentro del mismo assembly pero que no se pueda desde fuera, Veamos el código final.


   1:  public class PersonaFactory
   2:  {
   3:      public static Persona Create(string nombre)
   4:      {
   5:          Persona persona = new Persona();
   6:   
   7:          string connectionString = ConfigurationManager.ConnectionStrings["local"].ConnectionString;
   8:          string sql = "SELECT Edad, Apellido, FechaNacimiento FROM Persona where Nombre='" + nombre + "'";
   9:   
  10:          using (SqlConnection connection = new SqlConnection(connectionString))
  11:          {
  12:              connection.Open();
  13:              SqlCommand cmd = new SqlCommand(sql, connection);
  14:   
  15:              using (SqlDataReader reader = cmd.ExecuteReader())
  16:              {
  17:                  while (reader.NextResult())
  18:                  {
  19:                      persona.Apellido = (string)reader["Apellido"];
  20:                      persona.FechaNacimiento = Convert.ToDateTime(reader["FechaNacimiento"]);
  21:                      persona.Edad = (int)reader["Edad"];
  22:                  }
  23:                  reader.Close();
  24:              }
  25:              connection.Close();
  26:          }
  27:   
  28:          return persona;
  29:      }
  30:  }
Conclusión

Este es un primer vistazo de los patrones creacionales, los cuales nos permiten crear objetos desacoplando el modelo, imaginemos si mañana en lugar de conectarnos a una base de datos recuperamos los datos de un archivo de texto, la clase Persona no se va a enterar de esto, y está bien que así sea. En fin, en la próxima vamos a ver cómo se complica las cosas cuando entra en escena una jerarquía de objetos. Hasta entonces.

jueves, 2 de agosto de 2007

Introducción a Delegados, métodos anónimos, Predicados, etc.

Introducción

Los delegados son una característica muy interesante del framework que nos permiten pasar métodos como parámetros de otros métodos, extraño, puede ser, pero es menos complicado de lo que parece. En el framework 2 nos podemos encontrar con los delegados por todas partes, en diferentes formas, como delegados, como predicados, como acciones.

¿Qué es un delegado?

Como dije antes un delegado nos permite pasar un método como parámetro de otro método, ok, sabemos cómo hacer para pasar tipos de datos como parámetros, simplemente declaramos en tipo y el nombre, detengámonos un momento, si yo quisiera indicar que en cierto lugar espero un método para utilizarlo qué cosas tengo que establecer. La respuesta es clara, el tipo de retorno del método y los parámetros que acepta, bueno, esto es justamente un delegado, una firma que nos permite establecer cómo deberá ser el método que esperamos.

Ejemplo 1

Vamos a ver la declaración de un delegado para utlizarlo en un método nuestro como parámetro.

   1:  public delegate void MiDelegado(string mensaje);

Es muy claro que si quitamos la palabra delegate de esta declaración es idéntica a una declaración de un método cualquiera. Ahora vamos a crear un método que espere un delegado del tipo MiDelegado para invocar el método dentro.

   1:          public void TestDelegado(MiDelegado delegado)
   2:          {
   3:              delegado("hola delegado loco");
   4:          }


Ok, este método va a tomar como parámetro un delegado del tipo MiDelegado (o sea un método que devuelva void y tome un string como parámetro) y luego lo va a invocar. Veamos la llamada al método.
Primero creamos el método que utlizaremos como parámetro del tipo MiDelegado.


   1:  public void MetodoDelegado(string mensaje)
   2:  {
   3:          Console.WriteLine(mensaje);
   4:  }

Sencillo, el método recibe un string lo escribe en la consola y no devuelve nada. Ahora vamos a ver cómo se invoca.

   1:  private void Test()
   2:  {
   3:          MiDelegado delegado = new MiDelegado(MetodoDelegado);
   4:          TestDelegado(delegado);
   5:  }


Más sencillo aún, lo corremos y vemos que funciona.




Vemos que en la línea 3 declaramos el delegado y le pasamos como parámetro el método que cumple con el delegado, esto lo podríamos haber resumido así


   1:  TestDelegado(new MiDelegado(delegate(string message)
   2:  {
   3:      Console.WriteLine(message);
   4:  }));

Lo que hacemos aquí es definir en la misma línea el delegado y la implementación, esto es lo que se conoce como método anónimo. Es un método anónimo justamente porque no tiene nombre, si bien a simple vista puede parecer que el código se pone confuso, en muchas ocasiones es más práctico utilizar un método anónimo.

¿Y qué es un predicado?

Si utilizaron listas genéricas se habrán encontrado con que algunos método, como Find por ejemplo, toman como parámetro un predicado, bien, esto no es más que un delegado como el que acabamos de crear pero con una firma diferente, vamos a ver la definición,

 
   1:  public delegate bool Predicate<T>(T obj);


Está claro que es un delegado que define un método que acepte un tipo T (cualquiera) y que retorne bool. Esto es para indicar que el objeto que pasa como parámetro cumple con el criterio de búsqueda, vamos a ver el método Find de la lista genérica. Echamos mano del Reflector para variar y vemos esto:

   1:  public T Find(Predicate match) 
   2:  {
   3:      if (match == null)
   4:      {
   5:          ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
   6:      }
   7:      for (int i = 0; i < this._size; i++)
   8:      {
   9:          if (match(this._items[i]))
  10:          {
  11:              return this._items[i];
  12:          }
  13:      }
  14:      return default(T);
  15:  }




Vemos que el truco está en la línea 9, ahí llama al predicado y le pregunta si el item actual (dentro de la iteración) cumple con alguna condición que estará en el predicado. Vamos a ver una aplicación práctica

Ejemplo 2

Tenemos la siguiente entidad


   1:  class Persona
   2:  {
   3:      public int Edad;
   4:      public string Nombre;
   5:      public string Apellido;
   6:   
   7:      public Persona(string nombre, string apellido, int edad)
   8:      {
   9:          this.Edad = edad;
  10:          this.Apellido = apellido;
  11:          this.Nombre = nombre;
  12:      }
  13:   
  14:      public override string ToString()
  15:      {
  16:          return "Nombre=" + this.Nombre +" Apellido=" + this.Apellido +", Edad=" + this.Edad.ToString();
  17:      }
  18:  }

Ahora, creamos una lista de Persona y tratamos de recuperar, digamos, a mi.
 
   1:  List lista = new List(); 
   2:   
   3:  lista.Add(new Persona("Leonardo","Micheloni",31));
   4:  lista.Add(new Persona("Hernán", "Micheloni", 30));
   5:  lista.Add(new Persona("Adrián", "Micheloni", 34));
   6:   
   7:  Persona leonardo = lista.Find(new Predicate(delegate(Persona persona)
   8:  {
   9:      return persona.Nombre.Equals("Leonardo");
  10:  }));
  11:   
  12:  Console.WriteLine(leonardo);

Observemos este código, hasta la línea 6 se encuentra la creación de la lista de Persona, ahora en la línea 7 está el yeite. Primero invocamos al método Find de la lista genérica el cual espera un predicado, entonces lo declaramos como un método anónimo, simplemente le decimos que sea true si el nombre es igual a Leonardo, y listo, es todo.
Existe otro predicado predefinido en el framework que aparece en la lista genéricas, es el Action y se utiliza para aplicar una acción a los elementos de la colección.

Conclusión

Los delegados son elementos muy poderosos que nos permiten un grado de flexibilidad muy grande, recuerden el ejemplo de la lista, y todos los que se les ocurran; la utilidad de los métodos anónimos es grande también pero creo que no es bueno abusar porque queda un código algo confuso. Existe otra utilidad para los delegados que son los eventos pero eso será tema de otro post, hasta pronto.