Automatizando Pre y Post Procesos con Delegados Anónimos
Son comunes algunos pedazos de código que siempre: comienzan por lo mismo y terminan por lo mismo, pero... que pasa cuando en el medio varía dependiendo de su uso? Imaginemos una transacción de base de datos. Abres la connexión, insertas un registro, luego cierras la conexión. Abres la connexión, actualizas el registro, luego cierras la conexión. Abres la conexión, eliminas el registro, entonces cierras la conexión. Y repites cuantas veces sea necesario. Todas estas transacciones, comienzan y terminan en lo mismo, pero allí en el medio, algo cambia. Hay mucho código que reusar allí, pero organizar y planear el reusar este código no es totalmente obvio. He aquí una primera opción.
namespace ResourceExample
{
public abstract class AbstractDatabaseConnection : IDisposable
{
public void OpenConnection() {
Console.WriteLine("Opening connection...");
}
public abstract void ReadRecords();
public abstract void UpdateRecords();
public void CloseConnection() {
Console.WriteLine("Closing connection...");
}
#region IDisposable Members
public void Dispose() {
Console.WriteLine("Disposing of the connection...");
}
#endregion
}
public class MyDatabaseConnection : AbstractDatabaseConnection
{
public override void ReadRecords() {
Console.WriteLine("Reading records from the database...");
}
public override void UpdateRecords() {
Console.WriteLine("Updating records in the database..."); }
}
class Program {
static void Main(string[] args) {
using (MyDatabaseConnection myDatabaseConnection = new MyDatabaseConnection()) {
myDatabaseConnection.OpenConnection();
myDatabaseConnection.ReadRecords();
myDatabaseConnection.UpdateRecords();
myDatabaseConnection.CloseConnection();
}
}
}
}
Esto funciona, pero te deja ese saborcito, de que te falta algo más (por cierto, una sensación bastante común cuando desarrollo... será por eso que siempre trato de hacerlo reusable lo máximo posible?)... Pues ahora existen muchas maneras de limpiar esto. La más notoria y obvia, podríamos mover el método OpenConnection() al constructor y el método CloseConnection() al método Dispose() el cual prodría eliminar la necesidad de que quien consuma la clase tenga que llamarla explícitamente. Y esto es todo... sólo para comenzar... Pero aun hay formas más "elegantes" [que buena definición] de realizar esto utilizando una de las características más importantes... y una de mis favoritas de C#: Delegados Anónimos.
namespace ResourceExample {
public delegate void DatabaseConnectionUser(DatabaseConnection databaseConnection);
public class DatabaseConnection : IDisposable {
public void OpenConnection() {
Console.WriteLine("Opening connection...");
}
public void ReadRecords() {
Console.WriteLine("Reading records from the database...");
}
public void UpdateRecords() {
Console.WriteLine("Updating records in the database...");
}
public void CloseConnection() {
Console.WriteLine("Closing connection...");
}
#region IDisposable Members
public void Dispose() {
Console.WriteLine("Disposing of the connection...");
}
#endregion
public static void Use(DatabaseConnectionUser databaseConnectionUser) {
using (DatabaseConnection databaseConnection = new DatabaseConnection()) {
databaseConnection.OpenConnection();
databaseConnectionUser(databaseConnection);
databaseConnection.CloseConnection();
}
}
}
class Program
{
static void Main(string[] args) {
DatabaseConnection.Use(delegate(DatabaseConnection databaseConnection) {
databaseConnection.ReadRecords();
databaseConnection.UpdateRecords();
});
}
}
}
Vemos por un momento lo que ha sucedido. Simplemente se agregó un delegado y se lo hizo disponible a través del nuevo método Use(). Éste método maneja el pre-proceso y entonces se libera de manera que el usuario pueda ejecutar cualquier operación que se necesite. Una vez que el usuario ha finalizado, el delejado vuelve a manejar el método para manejar el post-proceso. Todo esto totalmente "empaquetado" de forma segura asegurando que el método Dispose() sea llamado al final. De esta manera, nos aseguramos que ambos, el pre-proceso y el post-proceso sean manejados automáticamente y con una liberación de recursos adecuada. Todo esto sin la adición de una clase nueva, nada más que una restructuración pequeña de una clase original y la adición de un delegado. Más temas sobre delegados y métodos anónimos:
- .Net C# Delegates and Events
- Delegates and Events in C# / .NET
- Create Elegant Code with Anonymous Methods, Iterators, and Partial Classes
- Anonymous Methods (C# Programming Guide)
- Introduction to anonymous methods in C#
Happy Coding!










