InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
También puedes ver ...
TransactionScope - Simplificando el trabajo con transacciones.
LinQ To SQL - Un ejemplo sencillo
Cómo activar Intelisense (autocompletado) en el Web.config
Leer un campo XML de SQL Server 2005 con C#
TripleDES - Un ejemplo practico en C#
Mostrar un GridView dentro de un DataList
String.Format
Métodos Extensores: INNER JOIN
Problemas en la instalación de Visual Studio 2008-Visual studio web authoring component
Redimiento de VS2008

Afiliados
La Web del programador
MundoProgramacion


 

  Delegados en C#.

  Introducción.

  Uno de los temas que más 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 través 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 definición seria: 

   Los delegados son un tipo que representa a una función con una determinada declaración.

   Vamos a analizar esta definición poco a poco, ya que dice mucho en muy pocas palabras ...

  • Los delegados son un TIPO.
  • Los delegados representan a una función.
  • La función debe tener una determinada declaración.

   Si un delegado es un tipo, entonces puedo crear variables de ese tipo. También hemos dicho que un delegado representa a una función, por lo que una variable creada de un tipo delegado es la representación de una determinada función. Por úlitmo hemos dicho que esta función debe tener una determinada declaración.

  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 función que devuelve un entero y que recibe como argumento también 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 excepción. Para asignar un delegado, no debemos asignar un "valor", sino un método, normalmente una funcion. El método al que asignemos el delegado no puede ser una función cualquiera, debe cumplir con la declaración del delegado. La forma de asignarlo es a través del constructor del delegado, pasando como argumento la función.

   A continuacion mostramos dos posibles funciones que cumplen con la declaración 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 declaración 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 pequeño 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 función delegateFunction1. Debido a que el método Main es estático, pero delegateFunction1 no lo es, necesitamos una instancia de la clase MainClass para referiros a la función de forma concreta. Por úlitmo ejecutamos nuestra variable (con un parámetro 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 podría hacerse invocando a la funcion sin más, 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 más complejo podría 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 función 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 declaración del delegado.

   Vamos ahora a ver un ejemplo algo más 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 método 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 además 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 métodos (que coinciden con la declaración 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 métodos y miembros:

  • logFunction, que es un miembro de tipo logDelegate y es la función encargada de realizar el log
  • Run, que es el método principal de la clase, unicamente comprueba que logFunction está asignada e itera 100 veces llamando al método Log.
  • SetLogMethod, este método es el más importante de todos, ya que recibe un parámetro de tipo logDelegate y lo asigna a logFunction para que pueda hacer su trabajo de forma correcta.
  • Log, este método ejecuta logFunction.

   El código 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 método Main en el que se inicia la ejecución del programa.

   El método 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 selección del usuario llama al método SetLogMethod  del objeto "programa" pasandole una nueva variable de tipo logDelegate construida con las funciones que proporciona la clase FormasLog.

   El código 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 ningún 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. Podríamos escribir una nueva funcion y decirle al componente que la utilice, solo tendríamos que llamar al metodo SetLogMethod.

   El código completo del programa se muestra a continuación:


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.

   Espero que este articulo os haya servido de ayuda para entender un poco mejor los delegados, y si teneis alguna duda al respecto no dudeis en exponerla en los foros.

   Saludos y hasta la proxima, Devjoker

 


 Versión para imprimir  Foros de consulta


Añadir comentario ... Para preguntar utiliza los foros
Autor:

Título:


Para preguntar utiliza los foros.



 Versión para imprimir

Delegados en C#
Autor: Pedro Herrarte Sánchez
Visitas: 4506 Fecha de publicación: 16/11/2005
Pedro Herrarte, es consultor independiente, ofreciendo sercivios de consultoría, análisis, desarrollo y formación.

Posee mas de diez años de experiencia trabajando para las principales empresas de España.

Es especialista en tecnologías .NET, entornos Web, bases de datos (SQL Server y ORACLE) e integración de sistemas.

Es experto en desarrollo (C#, ASP.NET, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE).

Es fundador, diseñador y programador de www.devjoker.com.




18/08/2008 SQL Server 2008
Visitas: 39 | Comentarios: 0 | Archivo: Articulos
Categorias: Transact-SQL
Visitas: 131 | Comentarios: 0 | Archivo: Articulos
Categorias: C#|ADO.NET|LinQ
Visitas: 161 | Comentarios: 1 | Archivo: Articulos
Categorias: Humor
Visitas: 154 | Comentarios: 0 | Archivo: Articulos
Categorias: WCF
Visitas: 123 | Comentarios: 0 | Archivo: Articulos
Categorias: WCF
Visitas: 210 | Comentarios: 0 | Archivo: Articulos
Categorias: ASP.NET
Visitas: 277 | Comentarios: 5 | Archivo: Articulos
Categorias: ASP.NET
Visitas: 4990 | Comentarios: 4 | Archivo: Articulos
Categorias: C#|Transact-SQL|LinQ
Visitas: 602 | Comentarios: 1 | Archivo: Articulos
Categorias: Visual Studio
Visitas: 1402 | Comentarios: 1 | Archivo: Articulos
Categorias: Transact-SQL

Útimos temas recibidos en los foros ...
Y lo mismo en WEB por systemat ... [C#] 1 18/08/2008
Manual del minicom de Linux con fotos. por Meta ... [UNIX] 4 17/08/2008
PROGRAMACION por JUANMA ... [Visual Basic .NET] 1 19/08/2008
Conectar ASP con B.D Informix por Franco ... [ASP] 9 02/05/2007
Codigo salir por Jazmin ... [ASP.NET] 1 18/08/2008
EXPORTAR DATOS A ARCHIVOS PLANOS. por WIX ... [ORACLE] 10 06/08/2007
formulario por artdark ... [C#] 2 04/08/2008
Codigo salir por Jazmin ... [ASP.NET] 0 18/08/2008
cambiar de modo un gried view por ivan ... [ASP.NET] 0 18/08/2008
ayuda urgente porfavor por vicancer ... [ASP.NET] 0 18/08/2008
pollo por hajaj ... [Actualidad] 1 15/08/2008
DIOS TE BENDIGA por El You ... [WIN 98/NT/2000/XP] 1 16/08/2008

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
04/07/2007 ¿Cómo se usa el RSS?    forma parte de...Tutorial RSS
03/04/2008 LINQ con métodos Extensores y expresiones lambda    forma parte de...Linq y Métodos extensores
14/05/2007 Fundamentos de Transact SQL    forma parte de...Tutorial de Transact SQL
01/01/2005 Conceptos básicos.    forma parte de...Iniciación a las bases de datos
01/01/2005 Introducción a las bases de datos    forma parte de...Iniciación a las bases de datos
01/01/2006 Borrado de datos. DELETE    forma parte de...Tutorial SQL
22/10/2005 Actualización de datos. UPDATE    forma parte de...Tutorial SQL
22/10/2005 Vistas    forma parte de...Tutorial SQL
01/06/2006 Cursores de actualización en PL/SQL    forma parte de...Tutorial PL/SQL
19/09/2007 Triggers en Transact SQL    forma parte de...Tutorial de Transact SQL

 

Encuesta
Si trabajas con .NET ¿Que entorno utilizas?
[Ver] [Votar]