2015-05-13 2 views
1

Поскольку я читал здесь и там немного, добавление или удаление методов из списка вызовов с ключевым словом new объекта-делегата на C# является точно таким же и создает тот же ИЛ. Смотрите этот, например: 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 или без него. Думаю, он, должно быть, работал правильно. Итак, в чем проблема?

Спасибо.

ответ

5

У вас есть два различных Синтаксисы здесь:

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

Те делают разные вещи - первый создает новый экземпляр делегата, основанный на групповом преобразовании в метод , Это полностью эквивалентно просто:

DelegateType x = MethodName; 

Второй создает новый экземпляр делегата, который эффективно «перенаправлены» к существующему экземпляру, и не равна ей. Это легко показать:

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>, например, без потери идентичности).

+0

", который также лучше обрабатывается, чем раньше" - Был ли «Действие ' не всегда контравариантным? – dcastro

+0

@ dcastro: Nope - только до .NET 4.0. Теоретически я считаю, что это могло быть в том, что CLR уже поддерживала общую дисперсию, но я не считаю, что соответствующие атрибуты когда-либо применялись в стандартных библиотеках. –

+0

@JonSkeet Я только что протестировал метод 'Equals' в' UnRegisterHandler' так: 'Console.WriteLine (« Equality: {0} », _handler.Equals (methods))', но он вернул «истину» в отличие , Зачем? – atoipowered

Смежные вопросы