You are on page 1of 9

[Escriba el ttulo del documento]

[Escriba el subttulo del documento]


[Escriba aqu una descripcin breve del documento. Normalmente, una descripcin breve es un resumen corto del contenido del documento. Escriba aqu una descripcin breve del documento. Normalmente, una descripcin breve es un resumen corto del contenido del documento.] mpajaro@hotmail.com [Seleccione la fecha]

Delegados en C#.
Introduccin.
Uno de los temas que ms suelen confundir a los nuevos programadores de la plataforma .NET, al menos a m, son los delegados. Para los programadores de C++ el concepto es muy similar al de los punteros a funciones, los programadores de JavaScript tienen una funcionalidad parecida a travs de objetos Function (que rara vez se utilizan), pero para el resto es totalmente nuevo. Lo primero que vamos a hacer es intenter definir que son los delegados. Una buena definicin seria: Los delegados son un tipo que representa a una funcin con una determinada declaracin. Vamos a analizar esta definicin poco a poco, ya que dice mucho en muy pocas palabras ... Los delegados son un TIPO. Los delegados representan a una funcin. La funcin debe tener una determinada declaracin. Si un delegado es un tipo, entonces puedo crear variables de ese tipo. Tambin hemos dicho que un delegado representa a una funcin, por lo que una variable creada de un tipo delegado es la representacin de una determinada funcin. Por litmo hemos dicho que esta funcin debe tener una determinada declaracin.

Un ejemplo sencillo.
Veamos un ejemplo que es como mejor se ven las cosas:

using System; namespace Devjoker.Ejemplos { delegate int myDelegate(int arg) ; }

En este caso hemos declarado un tipo delegado, al que hemos llamado myDelegate que representa a una funcin que devuelve un entero y que recibe como argumento tambin un entero. Como es un tipo no es necesario definirlo dentro de una clase. Como resultado vamos a poder declarar variables del tipo myDelegate. La siguiente pregunta seria,Como declaro variables de tipo myDelegate? y como asigno "valores" a esa variable?. Los delegados se declaran como cualquier otro objeto en .NET, recordemos que todo en .NET son objetos y los delegados no son una excepcin. Para asignar un delegado, no debemos asignar un "valor", sino un mtodo, normalmente una funcion. El mtodo al que asignemos el delegado no puede ser una funcin cualquiera, debe cumplir con la declaracin del delegado. La forma de asignarlo es a travs del constructor del delegado, pasando como argumento la funcin.

A continuacion mostramos dos posibles funciones que cumplen con la declaracin del delegado:

private int delegateFunction1(int a) { Console.WriteLine("Ejecutando ... delegateFuntion1"); return ++a; } private int delegateFunction2(int a) { Console.WriteLine("Ejecutando ... delegateFuntion2"); return a; }

Como podemos ver tanto delegateFuntion1 como delegateFunction2 son functiones que devuelven un tipo int y reciben como parametro un int, que es la forma en la que hemos declarado el delegado. La declaracin de una variable con el tipo delegado, es la siguiente, como cualquier otra variable en C#:

myDelegate variableDelegado;

Ahora vamos a ver como asignar un delegado. Hemos dicho que para asignar un delegado necesitamos utilizar el constructor del mismo. En el siguiente ejemplo vamos a ver un pequeo programa completo que declara y ejecuta un delegado: using System; namespace Devjoker.Ejemplos { delegate int myDelegate(int arg) ; class MainClass { public static void Main(string[] args) { MainClass instancia = new MainClass(); myDelegate variableDelegado; variableDelegado = new myDelegate(instancia.delegateFunction1); int a = variableDelegado(5); System.Console.WriteLine("El resultado obtenido es ... {0}",a); } private int delegateFunction1(int a) { Console.WriteLine("Ejecutando ... delegateFuntion1"); return ++a;

} private int delegateFunction2(int a) { Console.WriteLine("Ejecutando ... delegateFuntion2"); return a; } } }

En este ejemplo declaramos una variable variableDelegado y la asignamos a la funcin delegateFunction1. Debido a que el mtodo Main es esttico, pero delegateFunction1 no lo es, necesitamos una instancia de la clase MainClass para referiros a la funcin de forma concreta. Por litmo ejecutamos nuestra variable (con un parmetro fijo 5) y mostramos el resultado en pantalla. El programa genera una salida similar a la siguiente:

Ejecutando ... delegateFuntion1 El resultado obtenido es ... 6 Presione una tecla para continuar . . . Seguro que alguno de vosotros est pensando en que esto mismo podra hacerse invocando a la funcion sin ms, y no andar con tanto lio. Por supesto, pero este es un ejemplo muy sencillo y no pretende mostrar los casos complicados, recordemos que queremos aprender que son y para que sirven los delegados. Un caso ms complejo podra ser el siguiente, Imaginemos un control creado dinamicamente por el programa, sobre el que queramos programar su click ... La forma de hacerlo es con delegados. La funcin a la que asignamos el delegado no debe pertenecer a una clase en concreto, ni siquiera a un assemblie en particular, solo debe cumplir la declaracin del delegado. Vamos ahora a ver un ejemplo algo ms practico.

Un ejemplo practico.
El siguiente ejemplo, sin pretender entrar en mucha complejidad, es un sencillo programa que realiza su log de proceso bien por pantalla o en un fichero. El programa tiene tres clases: MainClass, que es la clase que contiene el mtodo main. ProgramClass, que es la clase que contiene el programa principal. FormasLog, que es la clase que contiene las diferentes formas para realizar el log del proceso. El programa tiene adems un delegado, que vamos a utilizar para realizar el log del proceso.Tienbe la siguiente forma:

delegate void logDelegate(string arg);

Veamos cada una de estas clases. Empezaremos con la clase FormasLog, que tiene dos mtodos (que coinciden con la declaracin del delegado), ConsoleLog y FileLog. ConsoleLog muestra un mensaje en pantalla y FileLog, escribe el mensaje en un fichero (ubicado en la misma ruta que el assemblie). El codigo de la clase es el siguiente: class FormasLog { private static StreamWriter fw; public static void ConsoleLog(string texto) { System.Console.WriteLine(texto); } public static void FileLog(string texto) { try { bool append = true; if (fw == null) { append = false; } fw = new StreamWriter( "ficherolog.log",append); fw.WriteLine(texto); fw.Close(); } catch (IOException e) { FormasLog.ConsoleLog(e.Message); } } }

La clase ProgramClass tiene los siguientes mtodos y miembros: logFunction, que es un miembro de tipo logDelegate y es la funcin encargada de realizar el log Run, que es el mtodo principal de la clase, unicamente comprueba que logFunction est asignada e itera 100 veces llamando al mtodo Log. SetLogMethod, este mtodo es el ms importante de todos, ya que recibe un parmetro de tipo logDelegate y lo asigna a logFunction para que pueda hacer su trabajo de forma correcta. Log, este mtodo ejecuta logFunction. El cdigo completo de la clase se muestra a continuacion:

class ProgramClass { logDelegate logFunction; public void Run() { if (logFunction == null) { logFunction = new logDelegate(FormasLog.ConsoleLog); } int i = 0; do { logFunction( "Este es el log! en la iteracion " + i.ToString()); } while (i++<100); } public void SetLogMethod(logDelegate metodo) { logFunction = metodo; } private void Log(string texto) { logFunction(texto); } }

Por ltimo tenemos la clase MainClass que es la clase que contiene el mtodo Main en el que se inicia la ejecucin del programa. El mtodo Main crea una instancia de la clase ProgramClass a la que llamamos "programa", y solicita al usuario que especifique una forma para realizar el log. Dependiendo de la seleccin del usuario llama al mtodo SetLogMethod del objeto "programa" pasandole una nueva variable de tipo logDelegate construida con las funciones que proporciona la clase FormasLog. El cdigo de la clase es: class MainClass { public static void Main(string[] args) { ProgramClass programa = new ProgramClass (); string valor = ""; do { Console.WriteLine("?Que forma de log quiere?"); Console.WriteLine("1->Consola 2->Fichero"); valor = System.Console.ReadLine();

} while (valor != "1" && valor!= "2" ); if (valor == "1") { programa.SetLogMethod( new logDelegate(FormasLog.ConsoleLog)); } else if (valor =="2") { programa.SetLogMethod( new logDelegate(FormasLog.FileLog )); } programa.Run ( ); } } La gran ventaja de esta forma de trabajar es que podemos cambiar la forma en la que el programa realiza el log desde el exterior del programa sin ningn tipo de esfuerzo. Imaginemos que las clase FormasLog y ProgramClass constituyen un componente de software compilado en un assemblie miComponente.dll. Por otro lado, la clase MainClass pertenece a otro assemblie completamente diferente, otroAssemblie.dll. En este escenario es posible que las formas de log que hemos predeterminado no sean suficientes como para cubrir las necesidades del programa, por ejemplo el log debe guardarse en una base de datos. Podramos escribir una nueva funcion y decirle al componente que la utilice, solo tendramos que llamar al metodo SetLogMethod. El cdigo completo del programa se muestra a continuacin:

namespace Devjoker.Ejemplos { delegate void logDelegate(string arg) ; class MainClass { public static void Main(string[] args) { ProgramClass programa = new ProgramClass (); string valor = ""; do { Console.WriteLine("Que forma de log quiere?"); Console.WriteLine("1->Consola 2->Fichero"); valor = System.Console.ReadLine(); } while (valor != "1" && valor!= "2" ); if (valor == "1") { programa.SetLogMethod( new logDelegate(FormasLog.ConsoleLog)); }

else if (valor =="2") { programa.SetLogMethod( new logDelegate(FormasLog.FileLog )); } programa.Run ( ); } } class ProgramClass { logDelegate logFunction; public void Run() { if (logFunction == null) { logFunction = new logDelegate(FormasLog.ConsoleLog); } int i = 0; do { logFunction( "Este es el log! en la iteracion " + i.ToString()); } while (i++<100); } public void SetLogMethod(logDelegate metodo) { logFunction = metodo; } private void Log(string texto) { logFunction(texto); } } class FormasLog { private static StreamWriter fw; public static void ConsoleLog(string texto) { System.Console.WriteLine(texto); } public static void FileLog(string texto) { try { bool append = true; if (fw == null) { append = false; } fw = new StreamWriter( "ficherolog.log",append); fw.WriteLine(texto); fw.Close(); }

catch (IOException e) { FormasLog.ConsoleLog(e.Message); } } } } Como hemos podido ver los delegados son una potentisima herramienta que ofrece, no solo C# sino la plataforma .NET.

You might also like