Basic premise:
I have a Room which publishes an event when an Avatar \"enters\" to all Avatars within the Room. When an Avatar leaves the Room I want it to remove a
What I'd like to do is in debug (do not think that this is good performance wise for release and one should catch it during development) throw exceptions when a class's events are not unsubscribed, this is the method that I use:
#if DEBUG
private void CheckEventHasNoSubscribers(Delegate eventDelegate)
{
if (eventDelegate != null)
if (eventDelegate.GetInvocationList().Length != 0)
{
var subscriberCount = eventDelegate.GetInvocationList().Length;
// determine the consumers of this event
var subscribers = new StringBuilder();
foreach (var del in eventDelegate.GetInvocationList())
subscribers.AppendLine((subscribers.Length != 0 ? ", " : "") + del.Target);
// throw an exception listing all current subscription that would hinder GC on them!
throw new Exception(
$"Event:{eventDelegate.Method.Name} still has {subscriberCount} subscribers, with the following targets [{subscribers}]");
}
}
#endif
The in my Dispose of the item that owns the delegate, or any other location where you're workflow supposed to release the object I would call it like this.
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (_orderCacheLock != null)
_orderCacheLock.Dispose();
if(_SettingTradeTimeOut!=null)
_SettingTradeTimeOut.Dispose();
_orderCacheLock = null;
#if DEBUG
CheckEventHasNoSubscribers(OnIsProfitable);
CheckEventHasNoSubscribers(OnPropertyChanged);
#endif
disposedValue = true;
}
}
It's then super easy to find the subscribers to these "orphaned" events and fix the code
ps: An Extension of this "practice pattern" looks like this.
public static void CheckEventHasNoSubscribers(this Delegate eventDelegate)
{
if (eventDelegate != null)
if (eventDelegate.GetInvocationList().Length != 0)
{
var subscriberCount = eventDelegate.GetInvocationList().Length;
// determine the consumers of this event
var subscribers = new StringBuilder();
foreach (var del in eventDelegate.GetInvocationList())
subscribers.AppendLine((subscribers.Length != 0 ? ", " : "") + del.Target);
// point to the missing un-subscribed events
throw new Exception( $"Event:{eventDelegate.Method.Name} still has {subscriberCount} subscribers, with the following targets [{subscribers}]");
}
}