2016-09-08 5 views
1

Я нашел следующий пример делегата/события в онлайн-книге C#. Но то, что я пропустил, это отмена подписки на объект MailWatch, когда он умирает, - что будет правильным способом отменить его подписку?C# делегат, события - как отказаться от подписки?

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

class NewEmailEventArgs : EventArgs 
{ 
    public NewEmailEventArgs (string subject, string message) 
    { 
     this.subject = subject; 
     this.message = message; 
    } 
    public string Subject { get { return (subject); } } 
    public string Message { get { return (message); } } 
    string subject; 
    string message; 
} 
class EmailNotify 
{ 
    public delegate void NewMailEventHandler (object sender, NewEmailEventArgs e); 
    public event NewMailEventHandler OnNewMailHandler; 

    protected void OnNewMail (NewEmailEventArgs e) 
    { 
     if (OnNewMailHandler != null) 
      OnNewMailHandler(this, e); 
    } 
    public void NotifyMail (string subject, string message) 
    { 
     NewEmailEventArgs e = new NewEmailEventArgs(subject, message); 
     OnNewMail(e); 
    } 
} 
class MailWatch 
{ 
    public MailWatch (EmailNotify emailNotify) 
    { 
     this.emailNotify = emailNotify; 
     emailNotify.OnNewMailHandler += new EmailNotify.NewMailEventHandler(IHaveMail); 
    } 
    void IHaveMail (object sender, NewEmailEventArgs e) 
    { 
     Console.WriteLine("New Mail:", e.Subject, e.Message); 
    } 
    EmailNotify emailNotify; 
} 
class Test 
{ 
    public static void Main() 
    { 
     EmailNotify emailNotify = new EmailNotify(); 
     MailWatch mailWatch = new MailWatch(emailNotify); 
     emailNotify.NotifyMail("Hello!", "Welcome to Events!!!") 
    } 
} 

И почему объект MailWatch получает второй NotifyMail? Объект MailWatch уже вышел из сферы действия, и я думаю, что он должен быть уже в байте-нирване?

class Test 
{ 
    public static void Main() 
    { 
     EmailNotify emailNotify = new EmailNotify(); 
     { 
      MailWatch mailWatch = new MailWatch(emailNotify); 
      emailNotify.NotifyMail("1!", "At live."); 
     } 
     emailNotify.NotifyMail("2!", "Still alive."); 
    } 
} 

Спасибо.

+4

Вы попробовали отказаться от подписки на оператор '- ='? – hellowstone

+1

Возможный дубликат [Отмена конференции] (http://stackoverflow.com/questions/15448258/event-unsubscribe) –

+0

Очень незначительная удобная настройка: 'emailNotify.OnNewMailHandler + = IHaveMail;' - значение идентично; просто проще набирать и читать –

ответ

1

Вам нужно будет взять под контроль время жизни MailWatch. Идеальным способом было бы через IDisposable, и он отписать себя при их удалении:

class MailWatch : IDisposable 
{ 
    public void Dispose() 
    { 
     emailNotify?.OnNewMailHandler -= IHaveMail; 
     emailNotify = null; 
    } 

и убедитесь, что вы Dispose() экземпляр - в идеале через using:

using(MailWatch mailWatch = new MailWatch(emailNotify)) 
{ 
    emailNotify.NotifyMail("Hello!", "Welcome to Events!!!") 
    // .. 
} 
emailNotify.NotifyMail("Oh no", "No-one is listening to me :(") 

Заметьте, что это не связано с мусором коллекция - и действительно, не может быть собранным мусором, если «вещь с событием» все еще знает об этом через делегата.

+0

Хорошо, это решает обе проблемы. Проблема отмены подписки и объема. – monotomy

1

Чтобы отменить подписку, изменить += подписки на -=:

emailNotify.OnNewMailHandler -= EmailNotify.NewMailEventHandler; 

Для получения дополнительной информации вы можете посмотреть на How to: Subscribe to and Unsubscribe from Events на MSDN.

+1

Я не думаю, что это работает, вам нужно будет сохранить ссылку на обработчик событий, чтобы вы могли отказаться от подписки именно на эту. Если вы создаете новый, когда отписывание ничего не изменяется (удалите somethin, это не так) Так просто 'var handler = new EventHandler (Method);' 'someEvent + = обработчик;' '/ * do stuff */' ' someEvent - = обработчик; ' – Stefan

+0

@Stefan неправильная копия/вставка. См. Править –

+0

Я не копировал/не вставлял;) Но да, вы уже исправили его. – Stefan

1

Предполагая, что Byte-Nirvana означает сбор мусора - нет, его еще нет, его экземплярный элемент используется в обработчике событий, поэтому он сохраняется в живых, пока этот обработчик подписан. Только после того, как вы отмените подписку на обработчик события, объект может быть собран в мусор.

+0

Да, я имею в виду мусор. Нужно получить мусорные вещи ... это немного отличается от C и C++ ... Вы должны получить вторую галочку. THX – monotomy

0

событий Подписка + = или Отменить - = только те использовали

emailNotify.OnNewMailHandler += new EmailNotify.NewMailEventHandler(IHaveMail); 

что подписаться события,

emailNotify.OnNewMailHandler -= new EmailNotify.NewMailEventHandler(IHaveMail); 

, который неподписывает события.

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