2010-02-03 27 views
56

Przeszedłem przez wiele artykułów, ale nadal nie jestem pewien różnicy między normalnymi delegatami, które zwykle tworzymy, a delegatami multicastowymi.Delegat Prosty (delegat) kontra delegat Multicast

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

Powyższy przedstawiciel MyMethodHandler wywoła te dwie metody. Teraz, gdzie wchodzą uczestnicy multiemisji. Czytałem, że mogą wywoływać wiele metod, ale obawiam się, że moje podstawowe zrozumienie dotyczące delegatów jest nieprawidłowe.

Odpowiedz

67

This article wyjaśnia to całkiem dobrze: specyfikacja

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

Czy Multicast delegaci nic więcej niż zwykłych delegatów, które mają wiele odniesień metody w ich liście wywołania? – A9S6

+3

Dokładnie. Delegat ds. Multiemisji powołuje się na wiele metod. –

+1

OK. Żeby było bardziej zrozumiałe: deklaruję zwykłego delegata i dodam do niego metodę ref, teraz będzie to nazywane delegatem Singlecast. Dodałem teraz inną metodę do tego samego delegata, to będzie teraz nazywane delegatem multiemisji? – A9S6

42

C# stwierdza, że ​​wszystkie rodzaje delegat musi być wymienialny na System.Delegate. W rzeczywistości sposób implementacji tego polega na tym, że wszystkie typy delegatów pochodzą z System.MulticastDelegate, która z kolei pochodzi od System.Delegate.

Czy to jasne? Nie jestem pewien, czy odpowiedział na twoje pytanie.

+23

Tak, Eric. Zwykle, gdy pytam ludzi (lub ludzie pytają mnie) o delegatów, zwykle mówimy, że istnieją dwa rodzaje delegatów - singlecast i multicast. Teraz wiem, że istnieje tylko jeden taki element, jak "delegat", który może być pojedynczym stosem lub multicastem w zależności od liczby zawartych w nim odnośników metod. – A9S6

11

"Wszystkie wystąpienia pełnomocników mają możliwość multiemisji." - http://msdn.microsoft.com/en-us/library/orm-9780596527570-03-04.aspx

„w języku C#, wszystkie typy delegata wsparcia grupowego” - http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx

+0

W jaki sposób * dowolna * instancja delegata może wywoływać dowolną liczbę działań innych niż liczba, do której została utworzona? Jeśli delegat został utworzony w celu wywoływania trzech rzeczy, myślę, że instancja delegata zawsze zrobi trzy rzeczy. Podobnie, jeśli został stworzony, aby zrobić jedną rzecz. Jeśli delegat został stworzony, aby wykonać dokładnie jedną rzecz, w jaki sposób ta instancja może zrobić więcej? – supercat

+0

@supercat, jej nie ma. –

+0

Co wtedy oznacza "wszystkie delegate * instancji * mają możliwość multiemisji"? Oczywiście, wszystkie delegaty * typy * mają taką zdolność, a kod, który akceptuje delegata dla czegokolwiek innego niż subskrypcja zdarzenia, musi być przygotowany, aby był delegatem multiemisji (jeśli zdarzenie korzysta z multiemisji delegatów wewnętrznie, przekazując delegata multiemisji do '' '' Metoda "add" i późniejsze przekazywanie jej do 'Remove' może faktycznie nie wypisać zdarzenia, że ​​domyślne funkcje obsługi zdarzeń w ten sposób sugerują, że zdarzenia nie powinny być tolerancyjne na zdarzenia multiemisji). – supercat

3

Aby wyjaśnić trochę: Wszystkie delegaci są instancjami klasy MulticastDelegate, niezależnie od tego, czy mają one jedną lub wiele metod docelowych. Zasadniczo nie ma różnicy między delegatem a jednym lub wieloma celami, chociaż środowisko wykonawcze jest zoptymalizowane nieco w kierunku wspólnego przypadku z pojedynczym celem. (Delegat z 0 miejscami docelowymi nie jest możliwy, jest to jeden lub więcej.)

Podczas tworzenia delegata takiego jak new MyMethodHandler(Method1), tworzysz delegata z pojedynczym celem (metoda Method1).

Delegaci z wieloma celami są tworzone przez połączenie dwóch istniejących delegatów. Wynikowy delegat będzie miał sumę celów. Delegaci mogą być łączone jawnie z Delegate.Combine(), ale także niejawnie, używając operatora += na istniejącym delegacie, jak w twoim przykładzie.

Wywołanie delegata po kolei wywołuje każdy cel w delegacie. Tak więc w twoim przykładzie handler(someObject); wywołasz dwie metody (Method1 i Method2), ponieważ utworzyłeś delegata z tymi dwoma celami.

-2

Delegat emisji multiemisji jest delegatem, który zawiera odwołania do więcej niż jednej funkcji. Podczas wywoływania delegata multiemisji wywoływane są wszystkie funkcje wskazane przez delegata.

Typ 1:

0 argumentem nieważności zwracany typ delegata -

Metoda 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"); 
    } 
} 

Metoda 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"); 
    } 
} 

Typ 2:

0 argumenty i typ Int powrotu pełnomocnik

Sposób 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; 
    } 
} 

Sposób 2-

sam proces, jak typ 1

Tak więc, gdy istnieje typ zwrotu dla Delegata MultiCast, wartość zwracana jest wartością zwracaną ostatniego uczestnika.

Typ 3:

int, int, sygn int argumenty i nieważne Zwraca typ delegata -

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 
*/