Delegado, Eventos en C#

download Delegado, Eventos en C#

of 70

Transcript of Delegado, Eventos en C#

ContenidoDelegados (Gua de programacin de C#) ...................................................................................................... 3 Delegate (Clase) ........................................................................................................................................................................ 4 Utilizar delegados (Gua de programacin de C#) .................................................................................................................... 7 Cundo se utilizan delegados en lugar de interfaces (Gua de programacin de C#) ............................................................ 10 Delegados con mtodos con nombre y delegados con mtodos annimos (Gua de programacin de C#) ......................... 10 Mtodos annimos (Gua de programacin de C#) ................................................................................................................ 12 Covarianza y contravarianza en los delegados (Gua de programacin de C#) ...................................................................... 14 Cmo: Combinar delegados (delegados de multidifusin) (Gua de programacin de C#).................................................... 16 Cmo: Declarar un delegado, crear instancias del mismo y utilizarlo (Gua de programacin de C#) ................................... 17 EventHandler (Delegado) ........................................................................................................................................................ 21 EventArgs (Clase)..................................................................................................................................................................... 23 Eventos (Gua de programacin de C#) ......................................................................................................... 25 Cmo: Suscribir y cancelar la suscripcin a eventos (Gua de programacin de C#).............................................................. 26 Cmo: Publicar eventos que cumplan las directrices de .NET Framework (Gua de programacin de C#) ........................... 29 Cmo: Producir eventos de una clase base en clases derivadas (Gua de programacin de C#) ........................................... 32 Cmo: Implementar eventos de interfaz (Gua de programacin de C#) ............................................................................... 35 Sincronizacin de subprocesos (Gua de programacin de C#) .............................................................................................. 39 Cmo: Utilizar un diccionario para almacenar instancias de eventos (Gua de programacin de C#) ................................... 43 Cmo: Implementar descriptores de acceso de eventos personalizados (Gua de programacin de C#) ............................. 45 Ejemplo de eventos ................................................................................................................................................................. 45 Diseo de eventos ................................................................................................................................................................... 47 Controlar y provocar eventos................................................................................................................................ 48 Eventos y delegados ................................................................................................................................................................ 49 Cmo: Conectar mtodos controlador de eventos a eventos ................................................................................................ 51 Para agregar un mtodo controlador de eventos para un evento ................................................................................. 51 Utilizar eventos ....................................................................................................................................................................... 51 Cmo: Consumir eventos en una aplicacin de formularios Web Forms ............................................................................... 55 Para controlar un evento de clic de botn en una pgina Web ..................................................................................... 55 Cmo: Consumir eventos en una aplicacin de formularios Windows Forms ....................................................................... 57 Para controlar un evento de clic de un botn en un formulario Windows Forms ......................................................... 57 Provocar un evento ................................................................................................................................................................. 59

Cmo: Implementar eventos en una clase ............................................................................................................................. 60 Para implementar un evento sin datos especficos del evento ...................................................................................... 60 Para implementar un evento con datos especficos del evento ..................................................................................... 61 Cmo: Provocar y utilizar eventos .......................................................................................................................................... 62 Provocar mltiples eventos..................................................................................................................................................... 66 Cmo: Controlar varios eventos mediante propiedades de eventos ..................................................................................... 67 Para controlar varios eventos mediante las propiedades de evento ............................................................................. 67 Cmo: Declarar eventos que evitan que se pierda memoria ................................................................................................. 68 Cmo: Controlar varios eventos mediante propiedades de eventos ..................................................................................... 69 Para controlar varios eventos mediante las propiedades de evento ............................................................................. 69

Delegados (Gua de programacin de C#) Un delegado es un tipo que define una firma de mtodo y se puede asociar a cualquier mtodo con una firma compatible. Puede invocar (o llamar) al mtodo a travs del delegado. Los delegados se utilizan para pasar mtodos como argumentos a otros mtodos. Los controladores de eventos no son ms que mtodos que se invocan a travs de delegados. Cree un mtodo personalizado y una clase como un control de Windows podr llamar al mtodo cuando se produzca un determinado evento. En el siguiente ejemplo se muestra la declaracin de un delegado: public delegate int PerformCalculation(int x, int y);

Cualquier mtodo de cualquier clase o estructura accesible que coincida con la firma del delegado, la cual est compuesta por los parmetros y el tipo de valor devuelto, puede asignarse al delegado. El mtodo puede ser un mtodo esttico o un mtodo de instancia. Esto permite el cambio mediante programacin de las llamadas a mtodos y la incorporacin de nuevo cdigo en las clases existentes. Si conoce la firma del delegado, puede asignar su propio mtodo. Nota: En el contexto de la sobrecarga de mtodos, la firma de un mtodo no incluye el valor devuelto. Sin embargo, en el contexto de los delegados, la firma s incluye el valor devuelto. En otras palabras, un mtodo debe tener el mismo valor devuelto que el delegado.

Esta capacidad para hacer referencia a un mtodo como parmetro hace que los delegados sean idneos para definir mtodos de devolucin de llamada. Por ejemplo, un algoritmo de ordenacin se podra pasar como referencia al mtodo que compara dos objetos. La separacin del cdigo de comparacin permite programar el algoritmo de forma ms general. Informacin general sobre delegados

Los delegados tienen las propiedades siguientes: Los delegados son similares a los punteros a funcin de C++, pero poseen seguridad de tipos. Los delegados permiten pasar los mtodos como parmetros. Los delegados pueden utilizarse para definir mtodos de devolucin de llamada. Los delegados pueden encadenarse; por ejemplo, se puede llamar a varios mtodos en un solo evento. No es necesario que los mtodos coincidan exactamente con la firma de delegado. Para obtener ms informacin, vea Covariance and ContravarianceCovarianza y contravarianza en los delegados (Gua de programacin de C#). La versin 2.0 de C# introdujo el concepto de mtodos annimos, los cuales permiten pasar bloques de cdigo como parmetros en lugar de utilizar mtodos definidos independientemente. C# 3.0 introdujo las expresiones lambda como una manera ms concisa de escribir bloques de cdigos insertados. Tanto los mtodos annimos como las expresiones lambda (en ciertos contextos) se compilan como tipos delegados. En conjunto, estas caractersticas se conocen ahora como funciones annimas. Para obtener ms informacin sobre las expresiones lambda, vea Funciones annimas (Gua de programacin de C#).

En esta seccin

Utilizar delegados (Gua de programacin de C#) Cundo se utilizan delegados en lugar de interfaces (Gua de programacin de C#) Delegados con mtodos con nombre y delegados con mtodos annimos (Gua de programacin de C#) Mtodos annimos (Gua de programacin de C#) Covarianza y contravarianza en los delegados (Gua de programacin de C#) Cmo: Combinar delegados (delegados de multidifusin) (Gua de programacin de C#) Cmo: Declarar un delegado, crear instancias del mismo y utilizarlo (Gua de programacin de C#)

Delegate (Clase) Representa un delegado, que es una estructura de datos que hace referencia a un mtodo esttico o a una instancia de clase y a un mtodo de instancia de dicha clase. Espacio de nombres: System Ensamblado: mscorlib (en mscorlib.dll) Sintaxis [SerializableAttribute] [ClassInterfaceAttribute(ClassInterfaceType.AutoDual)] [ComVisibleAttribute(true)] public abstract class Delegate : ICloneable, ISerializable Comentarios

La clase Delegate es la clase base para los tipos de delegado. No obstante, el sistema y los compiladores son los nicos que pueden derivar explcitamente a partir de la clase Delegate o de la clase MulticastDelegate. Tampoco est permitido derivar un tipo nuevo a partir de un tipo de delegado. La clase Delegate no se considera un tipo de delegado; es una clase que se utiliza para derivar tipos de delegado. La mayora de los lenguajes implementan una palabra clave delegate y los compiladores de dichos lenguajes pueden derivar a partir de la clase MulticastDelegate; por lo tanto, los usuarios deben emplear la palabra clave delegate que proporciona el lenguaje. Adems de los mtodos heredados, Common Language Runtime proporciona dos mtodos especiales para los tipos de delegado: BeginInvoke y EndInvoke. Para obtener ms informacin sobre estos mtodos, vea Llamar a mtodos sincrnicos de forma asincrnica. La declaracin de un tipo de delegado establece un contrato que especifica la firma de uno o varios mtodos. Un delegado es una instancia de un tipo de delegado que contiene referencias a: Un mtodo de instancia de un tipo y un objeto de destino asignable a ese tipo. Un mtodo de instancia de un tipo, con el parmetro this oculto expuesto en la lista de parmetros formales. Se dice que el delegado es un delegado de instancia abierto. Un mtodo esttico. Un mtodo esttico y un objeto de destino asignable al primer parmetro del mtodo. Se dice que el delegado se cierra en su primer argumento.

Para obtener ms informacin sobre el enlace de delegados, vea Delegados del sistema de tipos comn y CreateDelegate(Type, Object, MethodInfo, Boolean).

Nota: En las versiones 1.0 y 1.1 de .NET Framework, un delegado slo puede representar un mtodo si la firma del mtodo coincide exactamente con la firma que especifica el tipo de delegado. Por tanto, slo se admiten los puntos primero y tercero de la anterior lista y, en el caso del primero, es necesaria una coincidencia exacta de tipos.

Cuando un delegado representa un mtodo de instancia cerrado en su primer argumento (el caso ms habitual), el delegado almacena una referencia al punto de entrada del mtodo y una referencia a un objeto, el objeto de destino, que es de un tipo asignable al tipo que define el mtodo. Cuando un delegado representa un mtodo de instancia abierto, almacena una referencia al punto de entrada del mtodo. La firma del delegado debe incluir el parmetro this oculto en su lista de parmetros formales; en este caso, el delegado no tiene una referencia a un objeto de destino, por lo que se debe proporcionar un objeto de destino al invocar al delegado. Cuando un delegado representa un mtodo esttico, el delegado almacena una referencia al punto de entrada del mtodo. Cuando un delegado representa un mtodo esttico cerrado en su primer argumento, el delegado almacena una referencia al punto de entrada del mtodo y una referencia a un objeto de destino asignable al tipo del primer argumento del mtodo. Al invocar al delegado, el primer argumento del mtodo esttico recibe el objeto de destino. La lista de invocaciones de un delegado es un conjunto ordenado de delegados donde cada elemento de la lista invoca exactamente a uno de los mtodos representados por el delegado. Una lista de invocaciones puede contener mtodos duplicados. Durante una invocacin, los mtodos se llaman en el orden en que aparecen en la lista de invocaciones. Un delegado intenta invocar a todos los mtodos de la lista de invocaciones; se invoca a los duplicados una vez por cada aparicin en la lista de invocaciones. Los delegados son inmutables; una vez creados, la lista de invocaciones de un delegado no cambia. Se dice que los delegados son de multidifusin y combinables, porque un delegado puede invocar uno o varios mtodos y se puede utilizar para combinar operaciones. Las operaciones de combinacin, como Combine y Remove, no modifican los delegados existentes. En lugar de ello, una operacin de este tipo devuelve un nuevo delegado que contiene los resultados de la operacin, un delegado sin modificar o null. Una operacin de combinacin devuelve null cuando el resultado de la operacin es un delegado que no hace referencia a un mtodo como mnimo. Una operacin de combinacin devuelve un delegado sin modificar cuando la operacin solicitada no tiene efecto. Si un mtodo invocado produce una excepcin, el mtodo deja de ejecutarse, la excepcin se pasa de nuevo al llamador del delegado y no se invoca al resto de los mtodos de la lista de invocaciones. Aunque la excepcin se detecte en el llamador, este comportamiento no cambia. Cuando la firma de los mtodos invocados por un delegado incluye un valor devuelto, el delegado devuelve el valor devuelto del ltimo elemento de la lista de invocaciones. Cuando la firma incluye un parmetro que se pasa por referencia, el valor final del parmetro es el resultado que se obtiene despus de que cada mtodo de la lista de invocaciones se ejecute secuencialmente y actualice el valor del parmetro. El equivalente que ms se asemeja a un delegado en C o C++ es un puntero a una funcin. Un delegado puede representar un mtodo esttico o un mtodo de instancia. Cuando representa un mtodo de instancia, el delegado no slo almacena una referencia al punto de entrada del mtodo, sino que tambin almacena una referencia a la instancia de clase. A diferencia de los punteros a funciones, los delegados estn orientados a objetos y presentan seguridad de tipos.

Ejemplos

En el ejemplo siguiente se muestra la forma de definir un delegado denominado myMethodDelegate. Las instancias de este delegado se crean para un mtodo de instancia y un mtodo esttico de la clase mySampleClass anidada. El delegado correspondiente al mtodo de instancia requiere una instancia de mySampleClass. La instancia de mySampleClass se guarda en una variable denominada mySC. using System; public class SamplesDelegate { // Declares a delegate for a method that takes in an int and returns a String. public delegate String myMethodDelegate( int myInt ); // Defines some methods to which the delegate can point. public class mySampleClass { // Defines an instance method. public String myStringMethod ( int myInt ) { if ( myInt > 0 ) return( "positive" ); if ( myInt < 0 ) return( "negative" ); return ( "zero" ); } // Defines a static method. public static String mySignMethod ( int myInt ) { if ( myInt > 0 ) return( "+" ); if ( myInt < 0 ) return( "-" ); return ( "" ); } } public static void Main() { // Creates one delegate for each method. For the instance method, an // instance (mySC) must be supplied. For the static method, use the // class name. mySampleClass mySC = new mySampleClass(); myMethodDelegate myD1 = new myMethodDelegate( mySC.myStringMethod ); myMethodDelegate myD2 = new myMethodDelegate( mySampleClass.mySignMethod ); // Invokes the delegates. Console.WriteLine( "{0} is {1}; use the sign \"{2}\".", 5, myD1( 5 ), myD2( 5 ) ); Console.WriteLine( "{0} is {1}; use the sign \"{2}\".", -3, myD1( -3 ), myD2( -3 ) ); Console.WriteLine( "{0} is {1}; use the sign \"{2}\".", 0, myD1( 0 ), myD2( 0 ) ); } } /* This code produces the following output:

5 is positive; use the sign "+". -3 is negative; use the sign "-". 0 is zero; use the sign "". */ Jerarqua de herencia System.Object System.Delegate System.MulticastDelegate Seguridad para subprocesos Todos los miembros static (Shared en Visual Basic) pblicos de este tipo son seguros para la ejecucin de subprocesos. No se garantiza que los miembros de instancias sean seguros para la ejecucin de subprocesos.

Utilizar delegados (Gua de programacin de C#) Un delegado es un tipo de objeto que encapsula un mtodo de forma segura, similar a un puntero a funcin de C y C++. A diferencia de los punteros a funcin de C, los delegados estn orientados a objetos, proporcionan seguridad de tipos y son seguros. El tipo de un delegado se define por su nombre. El ejemplo siguiente declara un delegado denominado Del que puede encapsular un mtodo que toma un valor string como argumento y devuelve un valor void: public delegate void Del(string message);

Generalmente, un objeto de delegado se crea proporcionando el nombre del mtodo que el delegado contendr o con un mtodo annimo. Una vez que se crean instancias de un delegado, el delegado pasar al mtodo una llamada realizada por ste al delegado. Los parmetros que el llamador pas al delegado se pasan al mtodo y el delegado devuelve al llamador el valor devuelto del mtodo, si hay alguno. Esto se conoce como invocar al delegado. Se puede invocar un delegado con instancias como si fuera el propio mtodo contenido. Por ejemplo: // Create a method for a delegate. public static void DelegateMethod(string message) { System.Console.WriteLine(message); }

// Instantiate the delegate. Del handler = DelegateMethod; // Call the delegate. handler("Hello World");

Los tipos de delegados se derivan de la clase Delegate en .NET Framework. Los tipos de delegados son sealed (no se pueden derivar) y no es posible derivar clases personalizadas de Delegate. Puesto que el

delegado con instancias es un objeto, puede pasarse como parmetro o asignarse a una propiedad. Esto permite que un mtodo acepte un delegado como parmetro y llame al delegado posteriormente. Esto se conoce como devolucin de llamada asincrnica y constituye un mtodo comn de notificacin de un llamador cuando ha finalizado un proceso largo. Cuando se utiliza un delegado de esta forma, no es necesario que el cdigo que utiliza el delegado conozca la implementacin del mtodo que se est utilizando. La funcionalidad es similar a la encapsulacin que proporcionan las interfaces. Para obtener ms informacin, vea Cundo se utilizan delegados en lugar de interfaces (Gua de programacin de C#). Otro uso comn de devoluciones de llamada es definir un mtodo de comparacin personalizado y pasar ese delegado a un mtodo de ordenacin. Esto permite al cdigo del llamador ser parte del algoritmo de ordenacin. El mtodo del ejemplo siguiente utiliza el tipo Del como parmetro: public void MethodWithCallback(int param1, int param2, Del callback) { callback("The number is: " + (param1 + param2).ToString()); } A continuacin, se puede pasar el delegado creado anteriormente a ese mtodo: MethodWithCallback(1, 2, handler);

y recibir el resultado siguiente en la consola: The number is: 3 Al utilizar el delegado como abstraccin, MethodWithCallback no es necesario llamar a la consola directamente; es decir, el delegado no se tiene que disear pensando en una consola. Lo que MethodWithCallback hace es simplemente preparar una cadena y pasarla a otro mtodo. Esto es especialmente eficaz, puesto que un mtodo delegado puede utilizar cualquier nmero de parmetros. Cuando se crea un delegado para contener un mtodo de instancia, el delegado hace referencia tanto a la instancia como al mtodo. Un delegado no conoce el tipo de instancia a parte del mtodo que ste contiene, de modo que un delegado puede hacer referencia a cualquier tipo de objeto siempre que exista un mtodo en dicho objeto que coincida con la firma del delegado. Cuando se crea un delegado para contener un mtodo esttico, ste slo hace referencia al mtodo. Considere las siguientes declaraciones: public class MethodClass { public void Method1(string message) { } public void Method2(string message) { } } Junto con el mtodo esttico DelegateMethod que se mostr previamente, ahora tenemos tres mtodos que la instancia de Del puede contener. Un delegado puede llamar a ms de un mtodo cuando se invoca. Esto se denomina multidifusin. Para agregar un mtodo adicional a la lista de mtodos del delegado (lista de invocacin), simplemente es necesario agregar dos delegados mediante los operadores de suma o de asignacin de suma ('+' o '+='). Por ejemplo: MethodClass obj = new MethodClass(); Del d1 = obj.Method1; Del d2 = obj.Method2; Del d3 = DelegateMethod;

//Both types of assignment are valid. Del allMethodsDelegate = d1 + d2; allMethodsDelegate += d3;

En este momento, allMethodsDelegate contiene tres mtodos en su lista de invocacin: Method1, Method2 y DelegateMethod. Los tres delegados originales, d1, d2 y d3 no cambian. Cuando se invoca a allMethodsDelegate, se llama a los tres mtodos por orden. Si el delegado utiliza parmetros de referencia, sta a su vez se pasa secuencialmente a cada uno de los tres mtodos y todos los cambios efectuados por un mtodo son visibles para el siguiente mtodo. Cuando alguno de los mtodos produce una excepcin que no se detecta dentro del mtodo, esa excepcin se pasa al llamador del delegado y no se llama a ninguno de los mtodos siguientes de la lista de invocacin. Si el delegado tiene un valor devuelto y/o fuera de los parmetros, devuelve el valor devuelto y los parmetros del ltimo mtodo invocado. Para quitar un mtodo de la lista de invocacin, utilice el operador de resta o de asignacin de resta ('-' o '-='). Por ejemplo: //remove Method1 allMethodsDelegate -= d1; // copy AllMethodsDelegate while removing d2 Del oneMethodDelegate = allMethodsDelegate - d2;

Puesto que los tipos de delegados se derivan de System.Delegate, los mtodos y las propiedades definidos por esa clase se pueden llamar en el delegado. Por ejemplo, para buscar el nmero de mtodos en la lista de invocacin de un delegado, puede escribir: int invocationCount = d1.GetInvocationList().GetLength(0);

Los delegados con ms de un mtodo en su lista de invocacin derivan de MulticastDelegate, que es una subclase de System.Delegate. El cdigo anterior funciona en ambos casos porque las dos clases admiten GetInvocationList. Los delegados de multidifusin se utilizan ampliamente en el control de eventos. Los objetos de origen de eventos envan notificaciones de eventos a objetos de destinatario registrados para recibir ese evento. Para registrar un evento, el destinatario crea un mtodo diseado para controlar el evento, a continuacin crea un delegado para dicho mtodo y pasa al delegado al origen de eventos. El origen llama al delegado cuando se produce el evento. Luego el delegado llama al mtodo de control de eventos del destinatario y entrega los datos del evento. El origen de eventos define el tipo de delegado para un evento dado. Para obtener ms informacin, vea Eventos (Gua de programacin de C#). La comparacin de delegados de dos tipos distintos asignados en tiempo de compilacin producir un error de compilacin. Si las instancias de delegado son estticamente del tipo System.Delegate, se permite la comparacin, pero se devolver false en tiempo de ejecucin. Por ejemplo: delegate void Delegate1(); delegate void Delegate2(); static void method(Delegate1 d, Delegate2 e, System.Delegate f) { // Compile-time error. //Console.WriteLine(d == e); // OK at compile-time. False if the run-time type of f // is not the same as that of d.

System.Console.WriteLine(d == f); }

Cundo se utilizan delegados en lugar de interfaces (Gua de programacin de C#) Tanto los delegados como las interfaces permiten a un diseador de clases separar las declaraciones y las implementaciones de los tipos. Una interfaz determinada puede ser heredada e implementada por cualquier clase o estructura. Se puede crear un delegado para un mtodo en cualquier clase, con tal de que el mtodo se ajuste a la firma de mtodo para el delegado. Cualquier objeto puede utilizar una referencia de interfaz o un delegado sin tener conocimiento alguno sobre la clase que implementa el mtodo de interfaz o delegado. Segn estas similitudes, cundo debera un diseador de clases utilizar un delegado y cundo una interfaz? Utilice un delegado cuando: Se utilice un modelo de diseo de eventos. Se prefiere a la hora de encapsular un mtodo esttico. El autor de las llamadas no tiene ninguna necesidad de obtener acceso a otras propiedades, mtodos o interfaces en el objeto que implementa el mtodo. Se desea conseguir una composicin sencilla. Una clase puede necesitar ms de una implementacin del mtodo.

Utilice una interfaz cuando: Haya un grupo de mtodos relacionados a los que se pueda llamar. Una clase slo necesita una implementacin del mtodo. La clase que utiliza la interfaz desear convertir esa interfaz en otra interfaz o tipos de clase. El mtodo que se va a implementar est vinculado al tipo o identidad de la clase; por ejemplo, mtodos de comparacin.

Un buen ejemplo del uso de una interfaz de mtodo nico en lugar de un delegado es IComparable o la versin genrica, IComparable. IComparable declara el mtodo CompareTo, que devuelve un entero que especifica una relacin menor que, igual que o mayor que entre dos objetos del mismo tipo. IComparable se puede utilizar como base de un algoritmo de ordenacin. Aunque utilizar un mtodo de comparacin delegado como la base de un algoritmo de ordenacin sera vlido, no es lo ideal. Lo ideal es una interfaz de mtodo nico, ya que la capacidad de establecer comparaciones pertenece a la clase, y el algoritmo de comparacin no cambia en tiempo de ejecucin.

Delegados con mtodos con nombre y delegados con mtodos annimos (Gua de programacin de C#) Se puede asociar un delegado a un mtodo con nombre. Cuando se crean instancias de un delegado mediante un mtodo con nombre, el mtodo se pasa como parmetro; por ejemplo: // Declare a delegate: delegate void Del(int x); // Define a named method: void DoWork(int k) { /* ... */ }

// Instantiate the delegate using the method as a parameter: Del d = obj.DoWork; Esto se denomina utilizar un mtodo con nombre. Los delegados creados con un mtodo con nombre pueden encapsular un mtodo esttico o un mtodo de instancia. Los mtodos con nombre son la nica forma de crear instancias de un delegado en versiones anteriores de C#. Sin embargo, en una situacin en la que crear un mtodo nuevo constituye una sobrecarga no deseada, C# permite crear instancias de un delegado y especificar inmediatamente un bloque de cdigo que el delegado procesar cuando se le llame. El bloque puede contener una expresin lambda o un mtodo annimo. Para obtener ms informacin, vea Funciones annimas (Gua de programacin de C#). Comentarios

El mtodo, que se pasa como parmetro de delegado, debe tener la misma firma que la declaracin de delegado. La instancia de un delegado puede encapsular un mtodo esttico o de instancia. Aunque el delegado puede utilizar un parmetro out, no se recomienda su uso con delegados de eventos de multidifusin porque no se puede saber a qu delegado se va a llamar. Ejemplo 1

El siguiente es un ejemplo sencillo de declaracin y uso de un delegado. Observe que tanto el delegado, Del, como el mtodo asociado, MultiplyNumbers, tienen la misma firma // Declare a delegate delegate void Del(int i, double j); class MathClass { static void Main() { MathClass m = new MathClass(); // Delegate instantiation using "MultiplyNumbers" Del d = m.MultiplyNumbers; // Invoke the delegate object. System.Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':"); for (int i = 1; i