Delegados, Eventos y Métodos anónimos

Introducción: Implementando una interfaz gráfica con windows forms, teniendo un MDI principal y un par de formularios hijos, vi la necesidad que en un momento dado, un formulario hijo realice algo que el padre tiene que interceptar, y tomar cartas en el asunto. En este caso necesitaba setear la propiedad Text del MDI, a partir de alguna acción de un formulario hijo; algo sencillo.

En C# y sin la posibilidad de usar algo análogo al namespace My, que posee la gente de VB.Net, tuve que recurrir a un Eventos y Delegados,…y ya que estamos…Métodos anónimos.

En VB.Net, estando en formulario hijo con el namespace my seria algo bastante tonto:

My.Forms.MDIMain.Text = nombredeltitulo

En C# me las arregle con un mecanismo que permita que el padre (MDI principal) se quede a la “escucha” de un evento, y así iniciar acciones, pero con información que le provee el hijo. Es decir:

  • Los metodos a ejecutar: son del MDI principal
  • Y la información necesaria -los parametros- : provienen del form hijo.

Ahora bien, como se podrían implementar estos tres conceptos juntos para resolver esto ?

Ahora pasemos a un ejemplo donde se vé una interacción entre los objetos:

using System;// Declaracion del delegado

public delegate void EventHandler(string str);

public class Program
{

    public static void Main()
    {

        TestHandler tb = new TestHandler();

        //Tres maneras de hacer lo mismo

        //1- asignacion comun

        tb.Evento += new EventHandler(MetodoStringToUpper);

        //2- asignacion por inferencia de tipos

        tb.Evento += MetodoStringToLower;

        //3- asignacion con metodo anonimo

        tb.Evento += delegate(string str)
        {
            string otrostring = String.Format(“Metodo Anonimo: {0}”, str);
            Console.WriteLine(otrostring);
        };

        tb.Disparar(); Console.ReadLine();

    }

    public static void MetodoStringToUpper(string str)
    {
        Console.WriteLine(str.ToUpper());
    }

    public static void MetodoStringToLower(string str)
    {
        Console.WriteLine(str.ToLower());
    }

}

class TestHandler
{

    //Evento de tipo EventHandler

    public event EventHandler Evento;

    public void Disparar()
    {

        string mystring = “Dario.Net”;

        //Disparo el evento, con un string de parametro

        Evento(mystring);
    }

}

Primeramente declararemos un delegado: EventHandler, que podrá apuntar a metodos que contengan como argumentos el tipo string y que no retornen valores (void).

Luego en la clase TestHandler se declara un evento: Evento, del tipo EventHandler (nuestro delegado).

Y la funcion: Disparar(); se encargará de disparar el evento con un string como argumento: mystring=”Dario.Net”.

Vayamos al Main().

Instanciamos un objeto del tipo TestHandler, con el operador += y vamos agregando al evento, todos los métodos que queremos que se ejecuten, uno tras otro.

Luego invocamos a Disparar(). y se invocan, en este orden los tres métodos: MetodoStringToUpper,MetodoStringToLower y el querido metodo anónimo.

Cosas a notar:

El que dispara el evento es el TestHandler, y le pasa un parámetro: mystring.

Los métodos están en el Main, pero esos métodos se ejecutarán por el hijo…cosa loca no ?

El método anonimo: es como si fuera un metodo más, pero definido en el momento de su uso, e inline (buenísimo!)

Bien, ahora que vimos el ejemplo (y espero que lo hayan entendido), imaginemos algo: hagamos de cuenta que Program es el Main, y TestHandler es el Form1. Y podemos solucionar facilmente el problema que plantee al comienzo…y muchos más!

Para profundizar les recomiendo este artículo.

Saludos y dejen comentarios.

Developer Day

Ayer, 16 de agosto de 2006 se realizaron las jornadas de desarrollo en la UTN - Facultad Regional Resistencia - Chaco, donde se dieron lugar a interesantes charlas:

  • Web Semántica - Por César Acuña
  • Programación en SQL Server 2000 y 2005 - Por Mariano Minoli
  • Lo Nuevo de Visual Basic 2005 - Por Vanina Geneiro y Diego Poza
  • Layering y ORM: Un caso real - Por Dario Quintana
  • LINQ - Por Orlando Canteros y Guillermo Ruffino
  • Web Services - Por Agustín Casiva y Marcos Ibañez

En dichas jornadas estuve compartiendo un tema: Desarrollo en capas y Object/Relational Mapping. Donde se mostró un aplicación real que implementaba estos patrones. La verdad, me gustó mucho dar la charla. Hasta después se mostró algo de db4o también, para poder ejemplificar mejor sobre diferencias entre bases de datos relacionales y orientadas a objetos.

Y despues Orlando y Guillermo hablaron sobre LINQ, la verdad que está demasiado bueno el tema…y no veo la hora que salga la versión final de este proyecto para empezar a usarlo en serio.

Reflexion + Generación de código = Modelo para AjGenesis

Estuve viendo AjGenesis, que es un generador de codigo escrito por Angel “Java” Lopez, la verdad muy útil. Se puede generar código para cualquier lenguaje que estén escritas las plantillas, y sino están escritas, las podés escribir con mucha facilidad, ya que vienen algunas plantillas de ejemplo como para ir conociendo el lenguaje AjGenesis. Para poder generar código se requiere, como todo generador de cógido: un modelo. Este modelo está escrito en XML.

Por ahora, AjGenesis, no cuenta con una interfaz amigable para un usuario final, pero funciona y genera de lo lindo. Para comenzar a usarlo se haría así:

#AjGenesis.Console.exe ModelsModel.xml Tasksgenerate.ajg 

Donde Model.xml contiene los links a los otros archivos xml que contienen las descripciones de las entidades. Generate.ajg es el archivo de tareas que el generador vá a usar, vendría a ser como el archivo main para generar, él se encargará de buscar los templates. Por lo general el generate.ajg, tendrá un loop que iterará entre todas las entidades de negocio y así ir generando los artefactos en el lenguaje en que esten trabajando.

Ahora bien, como hago para obtener de forma automática el modelo?

En un proyecto que empecé con db4o, y el diseño de las business entities lo hacía con el Class Designer del Visual Studio 2005, se me ocurrió que el modelo de clases lo podía obtener del assembly donde están las clases de negocio. Es decir, tengo un proyecto que tiene adentro solo las clases de negocio, como podrían ser: Clientes, Factura, LineaFactura, etc.

Así nació GenerateFromAssembly, que es una herramienta muy sencilla, que via Reflexion, itera entre las clases de la dll, y obtiene sus propiedades con sus respectivos tipos de datos.

Actualmente la estoy usando en este proyecto, ya no con db4o, estoy usando NHibernate contra un Sql Server, pero la herramienta funciona igual, y genera el modelo como lo debe hacer.

Cabe destacar que la idea de la herramienta es: A partir del diseño de clases generar un assembly de .Net, y a partir de él, generar el modelo, y con el modelo y los templates de AjGenesis: obtengo mis artefactos, ya sean: Web Services, artefactos de capa de negocio, de capa de acceso a datos, o formularios web/windows.

Existe un issue: los tipos de datos genericos. Por ejemplo, si tengo IList<Cliente>, el CLR los trata como si fueran IList´1[Cliente], es una cuestión de nombres, nada más. De modo que en el código final generado con AjGenesis obtendremos los tipos de datos con este último esquema. Se podría hacer otra herramienta, que al codigo final generado, lo masajee con algunas expresiones regulares y exprese los generic tipes segun el lenguaje .Net que estemos usando.