2010-02-03 8 views
56

Я просмотрел множество статей, но я до сих пор не совсем понимаю о различиях между обычными делегатами, которые мы обычно создаем, и делегатами многоадресной рассылки.Простые делегаты (делегаты) и делегаты многоадресной передачи

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

Вышеупомянутый делегат MyMethodHandler будет называть эти два метода. Теперь, где входят делегаты многоадресной передачи. Я прочитал, что они могут вызывать несколько методов, но я боюсь, что мое основное понимание делегатов неверно.

ответ

67

This article объясняет это довольно хорошо:

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

ли Multicast делегаты ничего более обычных делегатов, которые имеют несколько ссылок методов в их списке вызовов? – A9S6

+3

Точно. Многоадресный делегат вызовет несколько методов. –

+1

OK. Просто, чтобы сделать это более ясным: я объявляю нормального делегата и добавляю метод ref к нему, теперь это будет называться делегатом Singlecast. Теперь я добавляю еще один метод к тому же делегату, теперь это будет передаваться как многоадресный делегат? – A9S6

42

C# спецификация предусматривает, что все типы делегатов должны быть конвертированы в System.Delegate. Фактически способ реализации реализуется таким образом, что все типы делегатов производятся от System.MulticastDelegate, что в свою очередь происходит от System.Delegate.

Это ясно? Я не уверен, что ответил на ваш вопрос.

+23

Да Эрик. Обычно, когда я спрашиваю людей (или меня спрашивают) о делегатах, мы обычно говорим, что есть два типа делегатов - одновещание и многоадресная рассылка. Теперь я знаю, что есть только одна такая вещь, как «делегат», который может быть как однострочным, так и многоадресным в зависимости от количества содержащихся в нем ссылок на методы. – A9S6

11

«Все экземпляры делегата имеют возможность многоадресной рассылки». - http://msdn.microsoft.com/en-us/library/orm-9780596527570-03-04.aspx

«В C# все типы делегата поддержки многоадресной рассылки» - http://msdn.microsoft.com/en-us/library/orm-9780596516109-03-09.aspx

+0

Каким образом * любой экземпляр делегата имеет любую возможность вызывать любое количество действий, кроме числа, которое он создал? Если делегат был создан для вызова трех вещей, я бы подумал, что экземпляр делегата всегда будет делать три вещи. Точно так же, если он был создан, чтобы сделать что-то одно. Если делегат был создан, чтобы сделать что-то одно, как этот экземпляр может когда-либо делать больше? – supercat

+0

@supercat, его нет. –

+0

Что означает «все делегированные экземпляры * имеют многоадресную возможность»? Конечно, все типы делегатов * имеют такую ​​возможность, а код, который принимает делегат для чего-либо, кроме подписки на события, должен быть подготовлен для того, чтобы он был делегатом многоадресной передачи (если событие использует делегаты многоадресной передачи внутри, передавая делегат многоадресной рассылки на ' Add', а затем передать его в «Удалить», на самом деле не может отказаться от подписки на событие, так что обработчики событий по умолчанию с таким неполадком подразумевают, что события не должны допускать многоадресные события). – supercat

3

Извините за добавление к чужой ответ, но я думал, что делегаты призваны в порядке их добавления.

раздел «Multicast Делегаты»

http://msdn.microsoft.com/en-us/library/orm-9780596527570-03-04.aspx

+5

Yup, и возвращает результат последней функции, если он имеет тип возврата - странный. – nawfal

3

Чтобы уточнить немного: Все делегаты являются экземплярами класса MulticastDelegate, независимо от того, имеют ли они один или несколько целевых методов. В принципе нет никакой разницы между делегатом с одной или несколькими целями, хотя среда выполнения немного оптимизирована для общего случая с одной целью. (Делегат с 0 целями невозможен, хотя он один или более.)

При создании экземпляра делегата, такого как new MyMethodHandler(Method1), вы создаете делегат с одной целью (метод Method1).

Делегаты с несколькими целями создаются объединением двух существующих делегатов. Получаемый делегат будет иметь сумму целевых показателей. Делегаты могут быть объединены явно с Delegate.Combine(), но также неявно с помощью оператора += в существующем делетете, как в вашем примере.

Вызов делегата, в свою очередь, вызывает каждую цель в делегате. Поэтому в вашем примере handler(someObject); вызовет два метода (Method1 и Method2), так как вы создали делегат с этими двумя целями.

-2

Многоадресный делегат является делегатом, который имеет ссылки на несколько функций. Когда вы вызываете делегат многоадресной рассылки, вызываются все функции, на которые указывает делегат.

Тип 1:

0 аргумент силы возвращаемый тип делегата -

Метод 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"); 
    } 
} 

Метод 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"); 
    } 
} 

Тип 2:

0 аргументы и возврата INT тип делегата

Метод 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; 
    } 
} 

Метод 2-

такой же процесс, как и тип 1

Поэтому, когда тип возврата делегата MultiCast является возвращаемым значением, это возвращаемое значение последнего делегата.

Тип 3:

INT, INT, реф ИНТ аргументы и аннулируются возвращаемый тип делегата -

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