c# - 为什么 C# 中的委托(delegate)语法允许 +=,而总是最后一个函数也会被指向

标签 c# .net delegates

我尝试了一个使用委托(delegate)的非常简单的示例,并且尝试使用类似于分配事件的+=,但总是触发最后一个函数。我想知道的是,如果 delegate 仅指向最后一个函数,为什么允许“+=”以及允许 += 的目的是什么

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
    class Program
    {
        public delegate int PointerToAddFunction(int a, int b);
        static void Main(string[] args)
        {
            PointerToAddFunction myPointerToAddFunction = null;
            myPointerToAddFunction = Add;

            Console.WriteLine(string.Format("Calling Add: Result is {0}", myPointerToAddFunction.Invoke(1, 3)));

            myPointerToAddFunction = Subtract;
            Console.WriteLine(string.Format("Calling Substract: Result is {0}", myPointerToAddFunction.Invoke(1, 3)));


            myPointerToAddFunction += Subtract;
            myPointerToAddFunction += Add;
            Console.WriteLine(string.Format("Calling Both: Result is {0}", myPointerToAddFunction.Invoke(1, 3)));

            Console.Read();
        }

        private static int Add(int a, int b)
        {
            return a + b;
        }

        private static int Subtract(int a, int b)
        {
            return a - b;
        }
    }
}

我想从 @CodesInChaos 的评论中添加一点

“为什么 CLR/C# 设计者决定支持不返回 void 的多播委托(delegate)”

最佳答案

What I am wondering about is the fact if delegate only points to the last function why "+=" is allowed and whats the purpose of allowing +=

使用+=运算符形成的委托(delegate)并不指向添加到其中的最后一个函数。当使用+=时,委托(delegate)被链接在一起形成一个新的委托(delegate)。该新委托(delegate)存储分配给它的所有函数的调用列表。

C# 规范指出:

Delegates are combined using the binary + (§7.8.4) and += operators (§7.17.2). A delegate can be removed from a combination of delegates, using the binary - (§7.8.5) and -= operators (§7.17.2). Delegates can be compared for equality (§7.10.8). The following example shows the instantiation of a number of delegates, and their corresponding invocation lists:

delegate void D(int x);
class C
{
    public static void M1(int i) {...}
    public static void M2(int i) {...}
}
class Test
{
    static void Main() {
        D cd1 = new D(C.M1);        // M1
        D cd2 = new D(C.M2);        // M2
        D cd3 = cd1 + cd2;      // M1 + M2
        D cd4 = cd3 + cd1;      // M1 + M2 + M1
        D cd5 = cd4 + cd3;      // M1 + M2 + M1 + M1 + M2
    }
}

When cd1 and cd2 are instantiated, they each encapsulate one method. When cd3 is instantiated, it has an invocation list of two methods, M1 and M2, in that order. cd4’s invocation list contains M1, M2, and M1, in that order. Finally, cd5’s invocation list contains M1, M2, M1, M1, and M2, in that order.

您在以下行中经历了什么:

Console.WriteLine(string.Format("Calling Both: Result is {0}",
                                 myPointerToAddFunction.Invoke(1, 3)));

是因为列表中最后调用的方法的值是调用委托(delegate)返回的值:

15.4 Delegate Invocation

If the delegate invocation includes output parameters or a return value, their final value will come from the invocation of the last delegate in the list.

关于c# - 为什么 C# 中的委托(delegate)语法允许 +=,而总是最后一个函数也会被指向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25712670/

相关文章:

c# - 无锁多线程适合真正的线程专家

c# - MongoDb C# 驱动程序解析命令插入失败 : document does not contain shard key

c# - 从流创建 Zip 文件并下载

c# - 允许用户安排方法

ios - 无法配置数据源和委托(delegate)

iPhone xcode - 从多个 View Controller 控制音频的最佳方式

c# - 如何计算文本文件中句子中的元音 (C#)

c# - 右键单击菜单项时如何显示上下文菜单

javascript - 如何找到最后单击的动态按钮

.net - 什么是 IDataErrorInfo 以及它如何与 WPF 一起使用?