Esos maravillosos eventos
Estoy haciendo una aplicación en C++/CLI a ratos, y ahora estaba construyendo un registro para guardar los eventos de la misma, al más puro estilo del Event Viewer de Windows. Podría utilizar ese mismo registro (con el .NET es una tarea trivial enviar mensajes al registro de eventos), pero como me gusta hacer los programas lo menos intrusivos posible, he decidido construirme uno propio.
La visión más orientada a objetos que se me ha ocurrido ha sido la de tener una clase llamada Log y encapsular ahí dentro todo el contenido. Dicha clase contiene una ventana en la que se va mostrando el registro en tiempo real si el usuario así lo quiere. La filosofía .NET requiere que los forms estén en sus propios ficheros fuente, de forma que si empezamos a añadir clases y otros elementos políticamente incorrectos lo más seguro es que terminemos con la caída del diseñador visual o incluso del entorno completo, así que decidí poner por un lado la ventana y todo su manejo y por otro la definición e implementación de la clase de registro.
Podría haberlo contenido todo dentro de la clase que define la ventana, pero aparte de que me parece algo sucio, si el usuario nunca muestra la ventana de registro, está gastando inútilmente una serie de recursos que muy bien se podrían ahorrar… aunque dada la voracidad del .NET no creo que se notara mucho.
Resumiendo: tengo una clase que es una ventana y otra que es un sistema de registro y que ha de controlar dicha ventana mediante una relación de contención (o sea: la clase registro contiene a la clase de la ventana).
Como la ventana ha de ser no modal, surge un problema: si el usuario cierra la ventana, o pulsa algún botón en ella, ¿cómo se lo comunico a la clase registro?
Una solución rápida (y que en su momento usé con el C++ Builder), es la de pasar un puntero (estoooo… una referencia) de la clase registro a la clase ventana. Pues no, el entorno me dice que es una referencia circular y eso no está permitido en C++, porque en C# sí que lo está. Un motivo como este determina que el C++/CLI sea un lenguaje para hombres. Ojo, no lo critico, porque realmente tener referencias circulares es una mala cosa, pero en otros lenguajes .NET sí que se permiten.
En fin, que el método clásico no funciona, y el de la relación padre/hijo tampoco, puesto que el padre no es una ficha, sino una clase normal y corriente (manejada pero normal y corriente pese a ello).
Bueno, cuando la inventiva de uno llega a su límite, decide recurrir a los Padres de la Patria y saca su flamante Petzold C# de la estantería y lo consulta. Tras leerse como cien páginas de aquí y de allá, recibe la inspiración charlésica: “-Joder, los eventos. M…. Así que para eso son los eventos…¡Claro, los closures del C++ Builder!”
En fin, que hay días…
Bueno, pues efectivamente, los eventos sirven, entre otras cosas, para eso, y son una forma elegante de solucionar el problema. El asunto es muy fácil.
void NombreMetodo(Object ^sender,EventArgs ^e)claseHija->Evento+=gcnew EventHandler(this,NombreMetodo)Y se acabó, cada vez que en la clase contenida se produzca el citado evento, nuestro método será llamado en correspondencia. Y lo curioso del tema no es que esto se pueda realizar en una relación de contención o de herencia, sino que puede ser enteramente global incluso entre ensamblados, por eso tenemos que pasar al EventHandler una referencia a la clase que contiene el método que se va a registrar. Pero aún hay más, porque el disparo de eventos no está limitado a controles o ventanas, sino que cualquier clase puede producir y consumir eventos. Quizás más adelante me hagan falta y lo explique aquí.
No obstante todo esto tan bonito, me surge la duda de la sobrecarga de código que pudiera llevar. Una closure en el C++ Builder no era más que un puntero doble: el primero almacenaba la dirección base del objeto, el segundo el offset del método, y a la hora de la ejecución, tan sólo había que calcular la dirección base más offset antes de lanzar el método (por cuestiones del contexto del objeto sobre el cual se iba a ejecutar el método). En el mundo .NET todas estas cosas están basadas en colecciones (un evento puede almacenar un número indeterminado de métodos a lanzar) y quizás no sea tan limpio ni óptimo como se deseara… Quizás algún día lo investigue.

Cada dia me gusta más el VB
Comment by Peni — April 28, 2006 @ 1:07 pm
Y el patrón MVC ahí muerto de risa, ¿nop?
Comment by Ramón Sola — April 29, 2006 @ 4:43 am
hola como estas…yo necesito hacer algo similar como proyecto de grado de la universidad…como capturar logs del sistema operativo…pero en JSP por que la aplicacion es orientada a web, me gustaria saber si puedo contar con vos….gracias a_josesanchez@yahoo.com.mx
Comment by alvaro — April 8, 2007 @ 12:55 am