InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
Tutorial C#
Introduccion a C#
Programacion con C#
Fundamentos de C#
Operadores
Instrucciones
Estrcuturas de control.
Definición de clases
Creación de objetos
Herencia y métodos virtuales
Polimorfismo
Ocultación de miembros
Miembros de tipo
Encapsulación
Espacios de nombres
Importación de espacios de nombres
Espacio de nombres distribuidos
Variables y tipos de datos
Tablas unidimensionales
Tablas multidimensionales
La clase System.Array
Cadenas de texto
Constantes
Orden de inicialización de variables
Métodos
Métodos externos
Constructores
Destructores
Propiedades
Indizadores
Redefinición de operadores
Delegados y eventos
La clase MulticastDelegate
Llamadas asíncronas
Implementación interna de los delegados
Eventos
Estructuras
Boxing y unboxing
Constructores de estructuras
Enumeraciones
Interfaces
Excepciones
Otras instrucciones
Atributos
Definición de nuevos atributos
Lectura de atributos en tiempo de ejecución
Atributos de compilación
Pseudoatributos
Código inseguro
Definición de punteros
Manipulación de punteros
Operadores relacionados con código inseguro
Fijación de variables apuntadas
Novedades de C# 2.0
Genéricos
Tipos parciales
Iteradores
Mejoras en la manipulación de delegados
Tipos anulables
Modificadores de visibilidad de bloques get y set
Clases estáticas
Referencias a espacios de nombres
Supresión temporal de avisos
Atributos condicionales
Incrustación de tablas en estructuras
Modificaciones en el compilador
También puedes ver ...
SubVersion y Visual Studio
Encriptación con AES Rijndael - Ejemplo
TripleDES - Un ejemplo practico en C#
Insertar una marca de agua en documentos PDF
Serialización: XmlSerializer y BinaryFormater
Handler para manipular imagenes
Conversiones de tipos personalizadas (VB y C#)
Compresión por gzip y deflate
La página Web que está abriendo contiene tanto elementos seguros como no seguros.
Cómo insertar un fichero .xml en un campo de tipo XML de SQL server 2005 o 2008


Delegados y eventos

Concepto de delegado

    Un delegado es un tipo especial de clase cuyos objetos pueden almacenar referencias a uno o más métodos de tal manera que a través del objeto sea posible solicitar la ejecución en cadena de todos ellos.

    Los delegados son muy útiles ya que permiten disponer de objetos cuyos métodos puedan ser modificados dinámicamente durante la ejecución de un programa. De hecho, son el mecanismo básico en el que se basa la escritura de aplicaciones de ventanas en la plataforma .NET. Por ejemplo, si en los objetos de una clase Button que represente a los botones estándar de Windows definimos un campo de tipo delegado, podemos conseguir que cada botón que se cree ejecute un código diferente al ser pulsado sin más que almacenar el código a ejecutar por cada botón en su campo de tipo delegado y luego solicitar la ejecución todo este código almacenado cada vez que se pulse el botón.

    Sin embargo, también son útiles para muchísimas otras cosas tales como asociación de código a la carga y descarga de ensamblados, a cambios en bases de datos, a cambios en el sistema de archivos, a la finalización de operaciones asíncronas, la ordenación de conjuntos de elementos, etc. En general, son útiles en todos aquellos casos en que interese pasar métodos como parámetros de otros métodos.

    Además, los delegados proporcionan un mecanismo mediante el cual unos objetos pueden solicitar a otros que se les notifique cuando ocurran ciertos sucesos. Para ello, bastaría seguir el patrón consistente en hacer que los objetos notificadores dispongan de algún campo de tipo delegado y hacer que los objetos interesados almacenen métodos suyos en dichos campos de modo que cuando ocurra el suceso apropiado el objeto notificador simule la notificación ejecutando todos los métodos así asociados a él.

Definición de delegados

    Un delegado no es más que un tipo especial de subclase System.MulticastDelegate. Sin embargo, para definir estas clases no se puede utilizar el mecanismo de herencia normal sino que ha de seguirse la siguiente sintaxis especial:


<modificadores> delegate <tipoRetorno> <nombreDelegado> (<parámetros>);

    <nombreDelegado> será el nombre de la clase delegado que se define, mientras que <tipoRetorno> y <parámetros> se corresponderán, respectivamente, con el tipo del valor de retorno y la lista de parámetros de los métodos cuyos códigos puede almacenar en su interior los objetos de ese tipo delegado (objetos delegados)

    Un ejemplo de cómo definir un delegado de nombre Deleg cuyos objetos puedan almacenar métodos que devuelvan un string y tomen como parámetro un int es:


delegate void Deleg(int valor);

    Cualquier intento de almacenar en este delegado métodos que no tomen sólo un int como parámetro o no devuelvan un string producirá un error de compilación o, si no pudiese detectarse al compilar, una excepción de tipo System.ArgumentNullException en tiempo de ejecución. Esto puede verse con el siguiente programa de ejemplo:


using System;
using System.Reflection;
public delegate void D();
public class ComprobaciónDelegados     
{
 public static void Main()
 {
  Type t = typeof(ComprobaciónDelegados);
  MethodInfo m = t.GetMethod("Método1");
  D obj  = (D) Delegate.CreateDelegate(typeof(D), m);
  obj();
 }
 
 public static void Método1()
 {
  Console.WriteLine("Ejecutado Método1");
 }
 
 public static void Método2(string s)
 {
  Console.WriteLine("Ejecutado Método2");
 }
}

    Lo que se hace en el método Main() de este programa es crear a partir del objeto Type que representa al tipo ComprobaciónDelegados un objeto System.Reflection.MethodInfo que representa a su método Método1. Como se ve, para crear el objeto Type se utiliza el operador typeof ya estudiado, y para obtener el objeto MethodInfo se usa su método GetMethod() que toma como parámetro una cadena con el nombre del método cuyo MethodInfo desee obtenerse. Una vez conseguido, se crea un objeto delegado de tipo D que almacene una referencia al método por él representado a través del método CreateDelegate() de la clase Delegate y se llama dicho objeto, lo que muestra el mensaje:


 Ejecutando Método1

    Aunque en vez de obtener el MethodInfo que representa al Método1 se hubiese obtenido el que representa al Método2 el compilador no detectaría nada raro al compilar ya que no es lo bastante inteligente como para saber que dicho objeto no representa a un método almacenable en objetos delegados de tipo D. Sin embargo, al ejecutarse la aplicación el CLR sí que lo detectaría y ello provocaría una ArgumentNullException

    Esto es un diferencia importante de los delegados respecto a los punteros a función de C/C++ (que también pueden almacenar referencias a métodos), ya que con estos últimos no se realizan dichas comprobaciones en tiempo de ejecución y puede terminar ocurriendo que un puntero a función apunte a un método cuya signatura o valor de retorno no se correspondan con los indicados en su definición, lo que puede ocasionar que el programa falle por causas difíciles de detectar.

    Las definiciones de delegados también pueden incluir cualquiera de los modificadores de accesibilidad válidos para una clase, ya que al fin y al cabo los delegados son clases. Es decir, todos pueden incluir los modificadores public e internal, y los se definan dentro de otro tipo también pueden incluir protected, private y protected internal.

Manipulación de objetos delegados

    Un objeto de un tipo delegado se crea exactamente igual que un objeto de cualquier clase sólo que en su constructor ha de pasársele el nombre del método cuyo código almacenará. Este método puede tanto ser un método estático como uno no estático. En el primer caso se indicaría su nombre con la sintaxis <nombreTipo>.<nombreMétodo>, y en el segundo se indicaría con <objeto>.<nombreMétodo>

    Para llamar al código almacenado en el delegado se usa una sintaxis similar a la de las llamadas a métodos, sólo que no hay que prefijar el objeto delegado de ningún nombre de tipo o de objeto y se usa simplemente <objetoDelegado>(<valoresParámetros>)

    El siguiente ejemplo muestra cómo crear un objeto delegado de tipo D, asociarle el código de un método llamado F y ejecutar dicho código a través del objeto delegado:


using System;
delegate void D(int valor);
class EjemploDelegado
{
 public static void Main()
 {
  D objDelegado = new D(F);
  objDelegado(3);
 }
 
 public static void F(int x)           
 {
  Console.WriteLine( "Pasado valor {0} a F()", x);
 }
}

    La ejecución de este programa producirá la siguiente salida por pantalla:


 Pasado valor 3 a F()

    Nótese que para asociar el código de F() al delegado no se ha indicado el nombre de este método estático con la sintaxis <nombreTipo>.<nombreMétodo> antes comentada. Esto se debe a que no es necesario incluir el <nombreTipo>. cuando el método a asociar a un delegado es estático y está definido en el mismo tipo que el código donde es asociado

    En realidad un objeto delegado puede almacenar códigos de múltiples métodos tanto estáticos como no estáticos de manera que una llamada a través suya produzca la ejecución en cadena de todos ellos en el mismo orden en que se almacenaron en él. Nótese que si los métodos devuelven algún valor, tras la ejecución de la cadena de llamadas sólo se devolverá el valor de retorno de la última llamada.

    Además, cuando se realiza una llamada a través de un objeto delegado no se tienen en cuenta los modificadores de visibilidad de los métodos que se ejecutarán, lo que permite llamar desde un tipo a métodos privados de otros tipos que estén almacenados en un delegado por accesible desde el primero tal y como muestra el siguiente ejemplo:


using System;
public delegate void D();
class A
{
 public static D obj;
 public static void Main()
 {
  B.AlmacenaPrivado();
  obj();
 }
}
class B
{
 private static void Privado()
 {
  Console.WriteLine("Llamado a método privado");
 }
 
 public static void AlmacenaPrivado()
 {
  A.obj += new D(Privado);
 }
}

    La llamada a AlmacenaPrivado en el método Main() de la clase A provoca que en el campo delegado obj de dicha clase se almacene una referencia al método privado Privado() de la clase B, y la instrucción siguiente provoca la llamada a dicho método privado desde una clase externa a la de su definición como demuestra la salida del programa:


 Llamado a método privado

    Para añadir nuevos métodos a un objeto delegado se le aplica el operador += pasándole como operando derecho un objeto delegado de su mismo tipo (no vale de otro aunque admita los mismos tipos de parámetros y valor de retorno) que contenga los métodos a añadirle, y para quitárselos se hace lo mismo pero con el operador -=. Por ejemplo, el siguiente código muestra los efectos de ambos operadores:


  using System;
 
  delegate void D(int valor);
 
  class EjemploDelegado
  {
   public string Nombre;
   EjemploDelegado(string nombre)
   {
    Nombre = nombre;
   }
   
   public static void Main()
   {
    EjemploDelegado obj1 += new EjemploDelegado("obj1");
    D objDelegado = new D(f);
    objDelegado +=  new D(obj1.g);
    objDelegado(3);
    objDelegado -= new D(obj1.g);
    objDelegado(5);
   }
   
   public void g(int x)
   {
    Console.WriteLine("Pasado valor {0} a g() en objeto {1}", x, Nombre);
   }
   
   public static void f(int x)
   {
    Console.WriteLine( "Pasado valor {0} a f()", x);
   }
 

La salida producida por pantalla por este programa será:


Pasado valor 3 a f()
 
 Pasado valor 3 a g() en objeto obj1
 
 Pasado valor 5 a f()

    Como se ve, cuando ahora se hace la llamada objDelegado(3) se ejecutan los códigos de los dos métodos almacenados en objDelegado, y al quitársele luego uno de estos códigos la siguiente llamada sólo ejecuta el código del que queda. Nótese además en el ejemplo como la redefinición de + realizada para los delegados permite que se pueda inicializar objDelegado usando += en vez de =. Es decir, si uno de los operandos de + vale  null no se produce ninguna excepción, sino que tan sólo no se añade ningún método al otro. 

    Hay que señalar que un objeto delegado vale null si no tiene ningún método asociado, ya sea porque no se ha llamado aún a su constructor o porque los que tuviese asociado se le hayan quitado con -=. Así, si al Main() del ejemplo anterior le añadimos al final:


objDelegado -= new D(f);
objDelegado(6);

    Se producirá al ejecutarlo una excepción de tipo System.NullReferenceException indicando que se ha intentado acceder a una referencia nula.

    También hay que señalar que para que el operador -= funcione se le ha de pasar como operador derecho un objeto delegado que almacene algún método exactamente igual al método que se le quiera quitar al objeto delegado de su lado izquierdo. Por ejemplo, si se le quiere quitar un método de un cierto objeto, se le ha de pasar un objeto delegado que almacene ese método de ese mismo objeto, y no vale que almacene ese método pero de otro objeto de su mismo tipo. Por ejemplo, si al Main() anterior le añadimos al final:


objDelegado -= new g(obj1.g);
objDelegado(6);

    Entonces no se producirá ninguna excepción ya que el -= no eliminará ningún método de objDelegado debido a que ese objeto delegado no contiene ningún método g() procedente del objeto obj1. Es más, la salida que se producirá por pantalla será:


 Pasado valor 3 a f()
 
 Pasado valor 3 a g() en objeto obj1
 
 Pasado valor 5 a f()
 
 Pasado valor 6 a f()


Inicio | Tutorial C# Redefinición de operadoresTutorial C#La clase MulticastDelegate Versión para imprimir Foros de consulta

 
errata por Victor Gras
Respuesta recibida el [08/10/2008 05:53:12]
Hola Jose Antonio, 

En el cuadradito de código donde dices

objDelegado -= new g(obj1.g);
objDelegado(6);

Debería ser: new D(obj1.g)

Vamos, cambiar la g, que referencia a un método, por la D, que es el delegado.

Gracias por tus tutoriales!

 
Gracias por Netsky
Respuesta recibida el [05/04/2009 08:11:28]
Muy bueno el tutorial, explica temas que en muchos libros no lo hacen, y profes mucho menos.... Que viva .NET

 
Excelente explicacion por Ivan Hernandez
Respuesta recibida el [03/08/2009 07:43:46]
quise tomarme varios minutos para expresar mi gran satisfaccion que he tenido por esta muy buena explicacion. Este tema lo he estudiado en algunos libros y no podia entenderlo muy bien, hasta que visite esta pagina que me ha servido de mucha ayuda. Excelente trabajo

 
Este articulo esta robado por NMG
Respuesta recibida el [28/08/2009 11:24:47]
el material es muy bueno, ya que se tomo copia tal cual del material original.

http://www.programacion.com/tutorial/csharp/13/

Saludos. Al menos pongan los creditos

 
Estimado Jose Antonio - mira e... por Devjoker
Respuesta recibida el [28/08/2009 12:05:43]
Estimado Jose Antonio - mira el pie de página ... Esta tu nombre no el mio :-)
Además, te solicite permiso por escrito hace ya unos años.
Saludos

 
String o void?? por Inquisidor
Respuesta recibida el [25/09/2009 01:47:14]
Primeramente gracias por los temas, solo quiero hacer una pregunta... en le primer ejemplo menciona que el delegado regresará un string, pero en el ejemplo la linea nos dice que se regresará un void. GRACIAS!!!

 
para NMG por JzThePunisher
Respuesta recibida el [24/10/2009 11:50:40]
oe idiota lee kien es el autor de ese curso..leeee!!!!carajo!!!!

 
Autor artículo por stdio696
Respuesta recibida el [13/01/2010 09:43:03]
En los dos casos es el mismo autor!!! buen artículo


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

Título:


Para preguntar utiliza los foros.



Inicio | Tutorial C# Redefinición de operadoresTutorial C#La clase MulticastDelegate Versión para imprimir

Delegados y eventos
Autor: José Antonio González Seco
Visitas: 21160 Fecha de publicación: 16/10/2006
José Antonio es experto en tecnologias Microsoft. Imparte cursos y conferencias en congresos sobre C# y .NET en Universidades de toda España (Sevilla, Barcelona, San Sebastián, Valencia, Oviedo, etc.) en representación de grandes empresas como Microsoft.




Visitas: 94 | Comentarios: 2 | Archivo: Articulos
02/02/2010 iPad vs Telesketch
Visitas: 796 | Comentarios: 2 | Archivo: Articulos
Categorias: Humor
Visitas: 752 | Comentarios: 3 | Archivo: Articulos
Visitas: 3153 | Comentarios: 2 | Archivo: Articulos
Categorias: C#
Visitas: 14516 | Comentarios: 7 | Archivo: Articulos
Categorias: C#|Seguridad
Visitas: 1483 | Comentarios: 3 | Archivo: Articulos
Visitas: 692 | Comentarios: 2 | Archivo: Articulos
Visitas: 369 | Comentarios: 0 | Archivo: Articulos
Visitas: 2021 | Comentarios: 2 | Archivo: Articulos
Categorias: C#

Útimos temas recibidos en los foros ...
pensiones por 29285524 ... [Access] 0 12/03/2010
certificado de porvenir por labar ... [Actualidad] 23 02/03/2010
Certificado de afiliacion Pensiones y Cesantias por VIVIANA ... [Actualidad] 2 10/03/2010
AYUDA COMANDOS BASICOS MSDOS!! por (L)MSDOS(L) ... [MS DOS] 24 12/03/2010
mananis por mananis ... [Actualidad] 0 12/03/2010
CERTIFICADO DE PENSIONES Y CESANTIAS PORVENIR por ABELLO ... [Actualidad] 0 12/03/2010
Solicitud certificado de afiliaciones a pensiones y cesantias proteccion por hz ... [Actualidad] 55 10/02/2010
certificado de pensiones y cesantias que me exigen para trabajar por viviana ... [Actualidad] 1 12/03/2010
Certificado de pensiones por liliana ... [Actualidad] 0 12/03/2010
certificado de afiliación de pensiones y cesantias por secre ... [Actualidad] 114 28/01/2010
certificado de pensiones horizonte por carla ... [Actualidad] 21 16/02/2010
certificado de pensiones del bbva horizonte por danger ... [Actualidad] 123 12/01/2010

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 ...
26/07/2006 PL/SQL y Java    forma parte de...Tutorial PL/SQL
26/07/2006 Secuencias    forma parte de...Tutorial PL/SQL
02/09/2007 Procedimientos almacenados en Transact SQL    forma parte de...Tutorial de Transact SQL
21/07/2006 Funciones integradas de PL/SQL    forma parte de...Tutorial PL/SQL
24/07/2006 SQL Dinamico    forma parte de...Tutorial PL/SQL
24/07/2006 Transacciones autónomas    forma parte de...Tutorial PL/SQL
20/07/2006 Transacciones con PL/SQL    forma parte de...Tutorial PL/SQL
06/09/2006 ¿Qué es el Collation en SQL ?
21/02/2007 BULK COLLECT    forma parte de...Tutorial PL/SQL
17/07/2006 Tipo VARRAY    forma parte de...Tutorial PL/SQL

 

Encuesta
¿A que perfil te adaptas mejor?




[Ver] [Votar]