2010-02-03 11 views
56

He revisado muchos artículos pero todavía no tengo clara la diferencia entre los delegados normales que generalmente creamos y los delegados de multidifusión.delegado simple (delegado) frente a delegados de multidifusión

public delegate void MyMethodHandler(object sender); 
MyMethodHandler handler = new MyMethodHandler(Method1); 
handler += Method2; 
handler(someObject); 

El delegado anterior MyMethodHandler llamará a estos dos métodos. Ahora, ¿dónde entran los delegados de multidifusión? He leído que pueden llamar a varios métodos, pero me temo que mi comprensión básica sobre los delegados no es correcta.

Respuesta

67

This article lo explica muy bien:

delegate void Del(string s); 

class TestClass 
{ 
    static void Hello(string s) 
    { 
     System.Console.WriteLine(" Hello, {0}!", s); 
    } 

    static void Goodbye(string s) 
    { 
     System.Console.WriteLine(" Goodbye, {0}!", s); 
    } 

    static void Main() 
    { 
     Del a, b, c, d; 

     // Create the delegate object a that references 
     // the method Hello: 
     a = Hello; 

     // Create the delegate object b that references 
     // the method Goodbye: 
     b = Goodbye; 

     // The two delegates, a and b, are composed to form c: 
     c = a + b; 

     // Remove a from the composed delegate, leaving d, 
     // which calls only the method Goodbye: 
     d = c - a; 

     System.Console.WriteLine("Invoking delegate a:"); 
     a("A"); 
     System.Console.WriteLine("Invoking delegate b:"); 
     b("B"); 
     System.Console.WriteLine("Invoking delegate c:"); 
     c("C"); 
     System.Console.WriteLine("Invoking delegate d:"); 
     d("D"); 
    } 
} 
/* Output: 
Invoking delegate a: 
    Hello, A! 
Invoking delegate b: 
    Goodbye, B! 
Invoking delegate c: 
    Hello, C! 
    Goodbye, C! 
Invoking delegate d: 
    Goodbye, D! 
*/ 
+10

son delegados de multidifusión nada más que delegados normales que tienen varias referencias de métodos en su lista de invocación? – A9S6

+3

Exactamente. Un delegado de multidifusión invocará múltiples métodos. –

+1

OK. Solo para dejarlo más claro: declaro un delegado normal y agrego un método ref, ahora esto se llamará un delegado Singlecast. Ahora agrego otro método al mismo delegado, ¿esto ahora será referido como un delegado de multidifusión? – A9S6

42

El C# especificación establece que todos los tipos delegadas deben ser convertibles a System.Delegate. De hecho, la forma en que la implementación implementa esto es que todos los tipos de delegados se derivan de System.MulticastDelegate, que a su vez deriva de System.Delegate.

¿Está claro? No estoy seguro de que haya respondido tu pregunta.

+23

Sí Eric. Normalmente cuando le pregunto a las personas (o la gente me pregunta) sobre los delegados, generalmente decimos que hay dos tipos de delegados: singlecast y multicast. Ahora sé que solo hay una cosa como un 'delegado' que puede ser singlecast o multicast dependiendo de la cantidad de referencias a métodos que contiene. – A9S6

11

"Todas las instancias de delegado tienen capacidad de multidifusión". - http://msdn.microsoft.com/en-us/library/orm-9780596527570-03-04.aspx

"En C#, todo tipo de delegado soporte multicast" - http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx

+0

¿Cómo * cualquier delegado instancia tiene alguna capacidad para invocar cualquier número de acciones que no sea el número para el que fue creado? Si se creó un delegado para invocar tres cosas, creo que la instancia de delegado siempre hará tres cosas. Del mismo modo, si fue creado para hacer una cosa. Si se creó un delegado para hacer exactamente una cosa, ¿cómo puede esa instancia hacer más? – supercat

+0

@supercat, no es así. –

+0

¿Qué significa "todas las instancias * delegadas * tienen capacidad multidifusión"? Ciertamente, todos los tipos * delegados tienen esa capacidad, y el código que acepta un delegado para cualquier otra cosa que no sea una suscripción a eventos debe prepararse para que sea un delegado de multidifusión (si un evento usa delegados de multidifusión internamente, pasa un delegado de multidifusión al ' El método 'Añadir' y luego pasarlo a 'Eliminar' podría no anular la suscripción al evento; el funcionamiento incorrecto de los manejadores de eventos de esta manera implica que no se espera que los eventos sean tolerantes a los eventos de multidifusión). – supercat

3

Para aclarar un poco: Todos los delegados son instancias de la clase MulticastDelegate, independientemente de si tienen uno o varios métodos de destino. En principio, no hay diferencia entre un delegado con un objetivo único o múltiples, aunque el tiempo de ejecución se optimiza un poco hacia el caso común con un único objetivo. (Sin embargo, un delegado con 0 objetivos no es posible, es uno o más.)

Cuando está creando instancias de un delegado como new MyMethodHandler(Method1), crea un delegado con un solo objetivo (el método Method1).

Los delegados con objetivos múltiples se crean al combinar dos delegados existentes. El delegado resultante tendrá la suma de objetivos. Los delegados pueden combinarse explícitamente con Delegate.Combine(), pero también implícitamente utilizando el operador += en un delegado existente, como en su ejemplo.

Invocando un delegado a su vez llama a todos los destinos en el delegado. Entonces en su ejemplo handler(someObject); llamará a dos métodos (Method1 y Method2), ya que ha creado un delegado con estos dos objetivos.

-2

Un delegado de multidifusión es un delegado que tiene referencias a más de una función. Cuando invoca a un delegado de multidifusión, se invocan todas las funciones a las que apunta el delegado.

Tipo 1:

0 argumento y sin efecto tipo de retorno delegado -

Método 1 -

using System; 

delegate void SampleDelegate(); //A delegate with 0 argument and void  return type is declared 

class MainClass 
{ 
    public static void Main() 
    { 
     SampleDelegate Del1 = new SampleDelegate (Message1);   //Del1 declared which points to function Message1 
     SampleDelegate Del2 = new SampleDelegate (Message2);  //Del2 declared which points to function Message2 
     SampleDelegate Del3 = new SampleDelegate (Message3);  //Del3 declared which points to function Message3 
     SampleDelegate Del4 = Del1 + Del2 + Del3;     //Del4 declared which points to function Message4 

     //Del4 is then initialized as sum of Del1 + Del2 + Del3 

     Del4();  //Del4 is invoked; 

     //Del4 in turn invokes Del1, Del2 and Del3 in the same order they were initialized to Del4 
     //Del1, Del2, Del3 in turn invokes their respective functions to which they point to 
     //The three functions Message1, Message2 and Message3 gets executed one after another 

    } 

     //Output: 
     //This is message 1 
     //This is message 2 
     //This is message 3 

     Del4 - Del1; //Removes Del1 from Del4 
     Del4();   

     //New Output: 
     //This is message 2 
     //This is message 3 

     Del4 + Del1; //Again adds Del1 to Del4 
     Del4(); 

     //New Output: 
     //This is message 1 
     //This is message 2 
     //This is message 3 


    public static void Message1()  //First sample function matching delegate signature 
    { 
     Console.WriteLine ("This is message 1"); 
    } 

    public static void Message2()  //Second sample function 
    { 
     Console.WriteLine ("This is message 2"); 
    } 

    public static void Message3()  //Third sample function 
    { 
     Console.WriteLine ("This is message 3"); 
    } 
} 

Método 2 -

using System; 

delegate void SampleDelegate(); 

class MainClass 
{ 
    public static void Main() 
    { 
     SampleDelegate del = new SampleDelegate (Message1);   //Declares del and initializes it to point to method Message1 
     del += Message2;          //Now method Message2 also gets added to del. Del is now pointing to two methods, Message1 and Message2. So it is now a MultiCast Delegate 
     del += Message3;          //Method Message3 now also gets added to del 

     del();             //Del invokes Message1, Message2 and Message3 in the same order as they were added 

     /* 
     Output: 
     This is Message1 
     This is Message2 
     This is Message3 
     */ 

     del -= Message1;          //Method  Message1 is now removed from Del. It no longer points to Message1 
                   //Del invokes the two remaining Methods Message1 and Message2 in the same order 
     del(); 
     /* 
     New Output: 
     This is Message2 
     This is Message3 
     */ 

     del += Message4;          //Method Message4 gets added to Del. The three Methods that Del oints to are in the order 1 -> Message2, 2 -> Message3, 3 -> Message4 
                   //Del invokes the three methods in the same order in which they are present. 
     del(); 
     /* 
     New Output: 
     This is Message2 
     This is Message3 
     This is Message4 
     */ 

    } 

    public static void Message1() 
    { 
     Console.WriteLine ("This is Message1"); 
    } 

    public static void Message2() 
    { 
     Console.WriteLine ("This is Message2"); 
    } 

    public static void Message3() 
    { 
     Console.WriteLine ("This is Message3"); 
    } 

    public static void Message4() 
    { 
     Console.WriteLine ("This is Message4"); 
    } 
} 

Tipo 2:

0 argumentos y tipo int retorno delegado

Método 1-

using System; 

delegate int SampleDelagate(); 

class MainClass 
{ 
    public static void Main() 
    { 
     SampleDelagate del1 = new SampleDelagate (Method1); 
     SampleDelagate del2 = new SampleDelagate (Method2); 
     SampleDelagate del3 = new SampleDelagate (Method3); 
     SampleDelagate del4 = del1 + del2 + del3; 

     int ValueReturned = del4(); 

     //Del4 invokes Del1, Del2, Del3 in the same order. Here the return type is int. So the return of last delegate del3 is returned. Del3 points to Method3. So returned value is 3. 

     Console.WriteLine (ValueReturned); 

     //Output: 3 
    } 

    public static int Method1() 
    { 
     return 1; 
    } 

    public static int Method2() 
    { 
     return 2; 
    } 

    public static int Method3() 
    { 
     return 3; 
    } 
} 

Método 2-

mismo proceso como Tipo 1

Entonces, cuando hay un tipo de devolución de un Delegado MultiCast, el valor de retorno es el valor de retorno del último delegado.

Tipo 3:

int, int, ref argumentos int y sin efecto tipo de retorno delegado -

using System; 

delegate void SampleDelegate (ref int SampleReferenceParameter); 

class MainClass 
{ 
    public static void Main() 
    { 
     SampleDelegate del1, del2, del3, del4; 
     del1 = new SampleDelegate (SampleMethodOne); 
     del2 = new SampleDelegate (SampleMethodTwo); 
     del3 = new SampleDelegate (SampleMethodTwo); 
     del4 = del1 + del2 + del3 - del3; 

     int SampleReferenceParameterValue = 0; 
     del4 (ref SampleReferenceParameterValue); 

     Console.WriteLine (SampleReferenceParameterValue); 
    } 

    public static void SampleMethodOne (ref int SampleReferenceParameter) 
    { 
     SampleReferenceParameter = 1; 
    } 

    public static void SampleMethodTwo (ref int SampleReferenceParameter) 
    { 
     SampleReferenceParameter = 2; 
    } 

    public static void SampleMethodThree (ref int SampleReferenceParameter) 
    { 
     SampleReferenceParameter = 3; 
    } 
} 

/* 
Here del4 is first set as sum of del1, del2 and del3. Then del3 is subtracted from del4. So del4 now has del1, del2. 

When del4 is invoked, first del1 and then del2 is invoked. 

del1 sets reference parameter to 1. del2 sets reference parameter to 2. 

But since del2 is called last final value of reference parameter is 2 
*/