简单委托(委托)与多播委托


69

我已经阅读了许多文章,但是我仍然不清楚我们通常创建的普通委托与多播委托之间的区别。

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

上面的委托MyMethodHandler将调用这两个方法。现在,多播委托从何而来。我读到它们可以调用多种方法,但恐怕我对委托的基本理解不正确。

Answers:


78

本文对此进行了很好的解释:

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

14
组播委托仅是在其调用列表中具有多个方法引用的普通委托吗?
A9S6'2

4
究竟。多播委托将调用多种方法。
Darin Dimitrov

55
.NET中的委托多播委托(据我所知)。无论您选择将零个处理程序还是一个或多个处理程序附加到它们,它们仍然是多播委托。
FredrikMörk'02

8
重要的是要注意,多播委托将以不可预测的顺序呼叫其订户。不要假定它们会以任何特定顺序被调用。
Mike Christian

13
@MikeChristian获得了“多播代表将以不可预测的顺序呼叫其订户”的链接?15.3的第二段似乎说它是按顺序调用的。
zastrowm 2014年

53

C#规范指出,所有委托类型都必须可以转换为System.Delegate。实际上,实现的实现方式是所有委托类型都从派生System.MulticastDelegate,而后者又从派生。System.Delegate

明白了吗?我不确定这是否回答了您的问题。


26
是的,埃里克。通常,当我向某人(或某人问我)有关委托的问题时,我们通常会说有两种委托类型:单播和多播。现在,我知道只有一种这样的东西,例如“代理”,可以根据其包含的方法引用的数量进行单播或多播。
A9S6'2

13

“所有委托实例都具有多播功能。” - http://msdn.microsoft.com/en-us/library/orm-9780596527570-03-04.aspx

“在C#中,所有委托类型都支持多播” -http://msdn.microsoft.com/zh-CN/library/orm-9780596516109109-03-09.aspx


除创建实例要执行的编号外,任何委托实例如何具有调用任何数量的动作的能力?如果创建了一个委托来调用三件事,那么我认为委托实例将总是做三件事。同样,如果创建它是为了做一件事。如果创建一个委托来做一件事情,那该实例又怎么做呢?
2014年

@supercat,不是。
StartupGuy 2014年

那么“所有委托实例都具有多播功能”是什么意思?当然,所有委托类型都具有这种能力,并且必须准备接受除事件订阅以外的任何东西的代码才能使其成为多播委托(如果事件在内部使用多播委托,则将多播委托传递给该Add方法,然后再传递给该方法传递给它Remove实际上可能不会取消订阅该事件;默认事件处理程序以这种方式发生故障意味着不希望事件容忍多播事件。
supercat 2014年

7

澄清一下:所有委托都是该类的实例MulticastDelegate,而不管它们是否具有一个或多个目标方法。原则上,具有单个或多个目标的委托之间没有区别,尽管针对具有单个目标的常见情况对运行时进行了一些优化。(尽管有一个或多个目标,但不可能有0个目标的委托。)

当实例化类似的委托时new MyMethodHandler(Method1),您将创建一个具有单个目标(Method1方法)的委托。

通过合并两个现有的代表来创建具有多个目标的代表。产生的代表将具有目标总数。可以将委托与显式组合Delegate.Combine(),但也可以通过+=在现有委托上使用运算符来隐式组合,如您的示例所示。

依次调用委托将调用委托中的每个目标。因此,在您的示例handler(someObject);中将调用两个方法(Method1Method2),因为您已经创建了具有这两个目标的委托。



-1

多播委托是具有对多个功能的引用的委托。当您调用多播委托时,该委托指向的所有功能都将被调用。

类型1:

0参数和void返回类型委托-

方法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,ref int参数和void返回类型委托-

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
*/
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.