C#委托,事件 - 如何取消订阅?

时间:2016-09-08 13:30:50

标签: c# events scope delegates

我在在线C#书中找到了以下委托/事件示例。但我想念的是在MailWatch对象死亡时取消订阅 - 取消订阅它的正确方法是什么?

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对象已经超出了范围,我认为它应该已经在Byte-Nirvana中了?

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 个答案:

答案 0 :(得分:1)

要取消订阅,请将订阅的+=更改为-=

emailNotify.OnNewMailHandler -= EmailNotify.NewMailEventHandler;

有关详细信息,请查看MSDN上的How to: Subscribe to and Unsubscribe from Events

答案 1 :(得分:1)

假设Byte-Nirvana意味着垃圾收集 - 不,它还没有,它的实例成员在事件处理程序中使用,所以只要该处理程序被订阅它就会保持活动状态。只有在您从事件中取消订阅处理程序后,才能对对象进行垃圾回收。

答案 2 :(得分: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 :(" )

请注意,这与垃圾收集无关 - 实际上,如果"事件" 不能进行垃圾收集。仍然通过代表了解它。

答案 3 :(得分:0)

活动订阅+ =或取消订阅 - =仅使用

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

即订阅活动,

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

这是取消订阅事件。