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

时间:2015-05-13 12:39:08

标签: c# delegates

正如我在这里和那里读到的那样,在C#中使用或不使用委托对象的while($row=mysql_fetch_array($Year)){ $a = explode(',', $row['YearRange']); foreach($a as $year){ $allYears[] = $year; // each row contributes to one large array } } // now work with $allYears $unique = array_unique($allYears); sort($unique); // generate your output foreach ($unique as $key => $value){ echo "<option>".$value."</option>"; } 关键字在调用列表中添加或删除方法完全相同并生成相同的IL。请参阅此示例:What is the difference between two ways of using delegates in C# (with new keyword and without)具有此代码片段:

$allYears

这两者之间没有区别。但是当我使用foreach()作为方法参数传递时,我意外地遇到了使用此代码观察异常输出:

new

如果我使用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我认为它必须正常工作。那么,这里的问题是什么?

感谢。

1 个答案:

答案 0 :(得分:5)

您在这里有两种不同的语法:

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

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

DelegateType x = MethodName;

第二个构建一个新的委托实例,它有效地被重定向&#34;到现有的实例,并不等于它。这很容易证明:

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>的参考转换,不会丢失身份信息。)