Yes, it is an extremely good idea. An event publisher holds a reference to the event subscriber which will prevent the subscriber from being garbage collected. (See Do event handlers stop garbage collection from occurring?)
In addition, if your event handlers use the resources you are releasing, then the event handlers (which will continue to be called by the event publisher) may generate exceptions after the resources have been released.
It is important, therefore, to unregister from any events before releasing your resources, especially if you are making use of async or multiple threads, as it is possible in some scenarios for an event to be raised between releasing a resource and unregistering from that event.
The following code demonstrates this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ReleaseEvents
{
class Program
{
public static event EventHandler SomethingHappened;
static void Main( string[] args )
{
using ( var l_dependent = new Dependent() )
{
SomethingHappened( null, EventArgs.Empty );
}
// Just to prove the point, garbage collection
// will not clean up the dependent object, even
// though it has been disposed.
GC.Collect();
try
{
// This call will cause the disposed object
// (which is still registered to the event)
// to throw an exception.
SomethingHappened( null, EventArgs.Empty );
}
catch ( InvalidOperationException e )
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine( e.ToString() );
}
Console.ReadKey( true );
}
}
class Dependent : IDisposable
{
private object _resource;
public Dependent()
{
Program.SomethingHappened += Program_SomethingHappened;
_resource = new object();
}
private void Program_SomethingHappened( object sender, EventArgs e )
{
if ( _resource == null )
throw new InvalidOperationException( "Resource cannot be null!" );
Console.WriteLine( "SomethingHappened processed successfully!" );
}
public void Dispose()
{
_resource = null;
}
}
}
The second time that the SomethingHappened event is raised, the Dependent class will throw an InvalidOperationException. You must unregister the event to prevent this from happening:
class Dependent : IDisposable
{
// ...
public void Dispose()
{
Program.SomethingHappened -= Program_SomethingHappened;
_resource = null;
}
}
I actually ran into this problem when I first tried to implement a MVVM architecture. When I was switching between ViewModels, I was simply releasing what I thought was my only reference (an ActiveViewModel property). I didn't realize that the events my ViewModel was subscribed to was keeping it in memory. As the application ran longer, it became slower and slower. Eventually I realized that the ViewModels I thought I had released were actually continuing to process events (expensively). I had to explicitly release the event handlers to fix this problem.