Mudanza: Migrando a Wordpress
http://blog.darioquintana.com.ar
Nos vemos ahí.
Saludos
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:
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;Primeramente declararemos un delegado: EventHandler, que podrá apuntar a metodos que contengan como argumentos el tipo string y que no retornen valores (void).
// 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 parámetro
Evento(mystring);
}
}
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.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:
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.
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 Models\Model.xml Tasks\generate.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`[Cliente], es una cuestión de nombras, 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.
En estos días estuve teniendo mis primeros encontronazos de verdad con db4o, antes habian sido solo pruebas, estoy inscripto al foro hispano oficial, y estuve -para inaugurar- haciendo unas preguntas, que la verdad me sacaron un poco del pozo en el que estaba. Tambien conocí a gente como Alan Lavintman, que me estuvo dando una mano por chat con esta base. Obviamente, yo no podía pasar sin hacer la pregunta que el 90 % de los nuevos que comienzan a usar db4o, viniendo de usar un motor de datos relacional: "como manejo en la inserción la duplicidad de objetos?" ay!...esa pregunta es la del millon!
Este concepto es distinto, no es el mismo que el de un motor relacional, donde se puede manejar una entidad referencial por medio de claves. Por que en una dbms la inserción de los datos en una tabla intermedia -por ejemplo-, se podría implementar por medio de un INSERT INTO y listo, a lo sumo el motor se encargará de lanzar una excepción en el caso de que se viole una regla de integridad, pero no pasa de ahí. Con db4o es muuuuy distinto, creanme, y tiene sus "porques" bien justificados, y no porque db4o lo justifique, es que hablando de objetos...no podría ser de otra forma.
Vean esto, tengo dos clases, A y B, despues tengo una clase C (que vendría a ser si se quiere, como una "tabla intermedia"), en este caso seria un objeto que tiene relación con los otros dos objetos (A y B), en UML sería visto como una asociación como clase. Ahora, seamos un poco creativos, e imaginemos que tenemos que no tenemos la necesidad de guardar los objetos, por que nuestra memoria es no-volatil y no tengo problemas de capacidad de memoria (ni de velocidad si se quiere), de modo que tengo todos los objetos en memoria, y en vez de insertar, tengo que asociarlos nada más. Entonces tendré que tener en la mano el objeto del tipo C (es el nuevo objeto) y tambien los objetos del tipo A y B para asociarlos. De modo que podriamos ver que la clase de C tendría una propiedad de tipo A y otra propiedad de tipo B (minimamente), tambien podría tener otros atributos, por ejemplo Descripcion.
La clase C podría declararse así:
public class C
{
private A _A;
private B _B;
private string _Descripcion;
public A A
{
get { return _A; }
set { _A = value; }
}
public B B
{
get { return _B; }
set { _B = value; }
}
public string Descripcion
{
get { return _Descripcion; }
set { _Descripcion = value; }
}
}
Ahora tendriamos que setear las propiedades de C:
[...]
C ObjC = new C();
ObjC.A = objA;
ObjC.B = objB;
ObjC.Descripcion = "Esto es una descripcion";
[...]
...y así estariamos realizando la asociacion de dichos objetos.
Ahora olvidando el concepto de object prevalence (que hablando rapido es: tener todos los objetos en memoria -bien básico-) y volviendo a la realidad... volviendo a nuestra db4o, para tener que hacer una inserción de un objeto que tiene una asociacion con otros objetos, tenemos que:
1) Cargar primeramente los otros objetos.
2) Asociar los objetos, -seteando los campos del objeto a insertar-.
3) Guardar el nuevo objeto en la base.
4) Listo, objeto y las referencias ya se han realizado.
Otra cosa que me pareció interesante destacar, que a db4o le importa muy poco como sobreescribamos los metodos Equals, no realiza comparaciones con él.
Tambien puede ser de ayuda, el concepto de callbacks, que db4o implementa. Son funciones que se disparan cuando ocurren ciertos eventos.
Por ejemplo, está el callback ObjectCanNew que devuelve un bool, y se dispara cada vez que se está por insertar un nuevo objeto, si el resultado de la función devuelve true, se guarda el objeto, de lo contrario no. En esa función tendríamos que agregar el procedimiento de validación.
Pero este concepto intrusivo de db4object, particularmente no me gusta mucho, por que tenemos que decorar todas nuestras entidades de negocio con estos metodos.. que son parte del acceso a datos, y poco tiene que hacer en cuanto a una validación de negocios. Pero...es una opción.
(?(? [\d]+)\u002e(? [\d]+)m)|
(?\d+)|
(?\u0028|\u0029|\u002a|\u002b|\u002d|\u002f|\u005e)|
\u0022(?.+)\u0022|
(?[a-zA-Z0-9\u002d\u002e]+)