2016-10-12 7 views
-3

В C# 5, каково поведение оператора - = при отписании от событий.C# - = оператор для отписки от одного события несколько раз

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

Property_Saved += Property_Saved_Handler; 
Property_Saved += Property_Saved_Handler; 
Property_Saved += Property_Saved_Handler; 

Теперь мы подписаны три раза.

После отписки со следующим одной строкой кода:

Property_Saved -= Property_Saved_Handler; 

Сколько подписок осталось? 2? никто? ...?

+2

Пытались ли вы это? –

+2

Ну, а что, если бы это были цифры? 'int x = 0; x + = 1; x + = 1; x + = 1; x - = 1; '. Это 'x' 2? или 0? –

+8

@MorganThrapp Что делать, если они были 'IEnumerable '? Если бы у бабушки были колеса, она была бы поездом. Поскольку делегат многоадресной рассылки не является целым числом, имеет смысл задаться вопросом, действует ли он как один или нет. Это не значит, что он не мог бы узнать сам, просто выполнив свой собственный код. –

ответ

11

После этого остаются два. Каждый -= удаляет только одну подписку. По крайней мере, это так, если он использует только обычный делегат для поддержки события.

Вы можете увидеть это легко на самом деле не связанных событий:

using System; 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     Action action =() => Console.WriteLine("Foo"); 
     // This is a stand-in for the event. 
     Action x = null; 
     x += action; 
     x += action; 
     x += action; 
     x -= action; 
     x(); // Prints Foo twice 
    } 
} 

Строго говоря, подписка на событие может сделать что-нибудь. Вы могли реализовать событие так:

private EventHandler weirdEvent; 
public event EventHandler WeirdEvent 
{ 
    add { weirdEvent += value; } // Subscribe as normal 
    remove { weirdEvent = null; } // I'm bored with *all* the handlers 
} 

Но обычно события просто делегировать Delegate.Combine и Delegate.Remove, которые являются методы, которые += и -= являются синтаксически в C#.

В моем article on events and delegates содержится более подробная информация о том, что происходит с комбинацией и удалением.

1
private void button1_Click(object sender, EventArgs e) 
{ 
    // set breakpoint 
} 

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

Вызов события click покажет двойную точку останова.

+0

Вы понимаете, что мы не можем видеть ваши точки останова, не так ли? – Abion47

+0

@ Abion47 Любой, кто достаточно яркий, чтобы заниматься программированием, достаточно яркий, чтобы выяснить, где находится точка останова. –

+1

@EdPlunkett Во-первых, вы серьезно переоцениваете умственную способность некоторых программистов. Во-вторых, есть много начинающих программистов, которые даже не знают, что такое точка останова. В-третьих, полагаться на существование точек останова, чтобы проиллюстрировать работу фрагмента кода, не помогает, поскольку вы сначала должны принять, где находятся точки останова, поэтому в подавляющем большинстве примеров кода используются основные математические, печатные заявления и комментарии. – Abion47

1

Просто сделать свой собственный тест, используя GetInvocationList

public delegate void MyEventHandler(string s); 
public event MyEventHandler MyEvent; 

MyEventHandler @event = s => { }; 

MyEvent += @event; 
Console.WriteLine(MyEvent.GetInvocationList().Length); 

MyEvent += @event; 
Console.WriteLine(MyEvent.GetInvocationList().Length); 

MyEvent -= @event; 
Console.WriteLine(MyEvent.GetInvocationList().Length); 

Это напечатает

1 
2 
1 
+0

Метод 'GetInvocationList()' является прекрасным ** здесь. Я видел код очистки утечки памяти, который просто петли через возвращенную коллекцию и удаляет каждого делегата. – mdisibio