无法从委托对象调用列表中正确删除方法

Can't remove methods from delegate object invocation list properly

正如我在这里和那里读到的那样,在 C# 中使用或不使用委托对象的 new 关键字在调用列表中添加或删除方法是完全相同的,并且会产生相同的 IL。例如看这个:What is the difference between two ways of using delegates in C# (with new keyword and without) 有这段代码:

this.button1.Click += new System.EventHandler(this.button1_Click);
this.button1.Click += this.button1_Click;

两者没有区别。但是当我使用 delegate 作为方法参数传递时,我不小心发现使用此代码观察异常输出:

private delegate void TextPrinter(string text);
private static TextPrinter _handler;

static void Main(string[] args)
{
    TextPrinter myPrinter = PushMessage;
    RegisterHandler(PushMessage);
    UnRegisterHandler(PushMessage);
    InvokePrinter("hello");
}

private static void RegisterHandler(TextPrinter methods)
{
    _handler += methods;
}

private static void UnRegisterHandler(TextPrinter methods)
{
    /* first routine >> */_handler -= new TextPrinter(methods);
    /* second routine >> */ //_handler -= methods;
}

private static void InvokePrinter(string message)
{
    _handler(message);
}

private static void PushMessage(string message)
{
    Console.WriteLine("# :: {0}", message);
}

如果我使用 UnRegisterHandler 中的第二个例程,一切都会按预期进行。但是当我使用第一个时,PushMessage 方法不会从 _handler 的调用列表中删除,尽管有或没有 new 我想它一定工作正常。那么,这里的问题是什么?

谢谢。

这里有两种不同的语法:

  • DelegateType x = new DelegateType(MethodName)
  • DelegateType x = new DelegateType(ExistingDelegateInstance)

它们做不同的事情 - 第一个基于 方法组转换 构建一个新的委托实例。这完全等同于:

DelegateType x = MethodName;

第二个构建一个新的委托实例,该实例实际上 "redirected" 现有实例,但不等于它。这很容易证明:

using System;

public class Test
{
    static void Main()
    {        
        Action action1 = Main;
        Action action2 = new Action(Main);
        Action action3 = new Action(action1);

        Console.WriteLine(action1.Equals(action2)); // True
        Console.WriteLine(action1.Equals(action3)); // False
    }
}

创建一个引用另一个委托实例的新委托实例很少是个好主意,除非它是为了委托差异 - 这也比以前通过引用转换更好地处理(有一个引用转换例如,从 Action<string>Action<object>,不会丢失身份)。