tommy_tee tommy_tee - 2 months ago 13
C# Question

C# delegate, events - how to unsubscribe?

I've found the following delegate/event example in an online C# book. But what I miss is unsubscribing the MailWatch object when it dies - what will be the correct way to unsubscribe it?

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!!!" )
}
}


And why does the MailWatch object receive the second NotifyMail? The MailWatch object is already out of scope and I think it should be already in the 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." );
}
}


Thanks.

Answer

You're going to have to take control over MailWatch's lifetime. The ideal way would be via IDisposable, and have it unsubscribe itself when disposed:

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

and make sure you Dispose() the instance - ideally via using:

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

Note that this is not related to garbage collection - and indeed, it cannot be garbage collected if the "thing with the event" is still aware of it via the delegate.

Comments