A while ago I noticed an issue with .NET that just stung me yet again
today. I had an object that I wanted to be garbage collected but it
registered itself for several events of external objects which entails
giving those objects a delegate that contains a reference to the event
consuming object. The solution I have seen in Microsoft samples is to
unregistered for the events in the Dispose method. Unfortunately, this
creates a situation where manual memory management for these objects
is a requirement. Dispose must be called or they will never be garbage
collected. Garbage collection is supposed to eliminate much of the
need for memory management, but it is not perfect and this is one of
the cases where it fails miserably and quite often.

I came up with a half-solution. I call it the WeakDelegate and it
works well, but in order for its potential to be truly realized it
would need framework level adoption. The concept is that it is a
special kind of delegate that maintains a weak reference instead of a
strong one. Then you simply unregistered for the events in a Dispose
method and call the Dispose method from the finalizer. Worst case is
that the overhead of a finalizer is called.

Maybe in future versions of .NET, delegates defined as:

delegate returnType DelegateName(parameterList);

will really define an abstract class derived from Delegate (or
MulticastDelegate or whatever) as well as two dirivatives of
DelegateName being WeakDelegateName and StrongDelegateName. Generics
may help.

I would love to hear feedback, expecially from a Microsoft rep, with
regards to this idea.

Also, I dug up a prototype from my archives from when I was first
learning C#:



using System;
using System.Reflection;
using System.Collections;

namespace BDB
{
/// <summary>Delegate that will not prevent garbage
collection</summary>
/// <remarks>Static Members not supported:
/// Use instance wrapper methods if this functionality is required.
///
/// Invoke method called on collected objects or missing methods will
fail silently.</remarks>
public class WeakDelegate
{
/// <summary>Construct a WeakDelegate</summary>
/// <param name="d">"Strong" Delegate to copy from</param>
public WeakDelegate(Delegate d)
{
referance = new WeakReference(d.Target);
methodName = d.Method.Name;
}

/// <summary>Construct a WeakDelegate</summary>
/// <param name="o">Object to invoke method on</param>
/// <param name="m">Method to invoke</param>
public WeakDelegate(object obj, string methodName)
{
this.referance = new System.WeakReference(obj);
this.methodName = methodName;
}

/// <summary>Call the method referanced by this
WeakDelegate</summary>
/// <param name="args">Arguments to pass called method</param>
/// <returns>Results of method call</returns>
public object Invoke(object[] args)
{
MethodInfo m = referance.Target.GetType().GetMethod(methodName,
BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
return (m==null? null : m.Invoke(referance.Target, args));
}

/// <summary>Determins if the object to invoke the method on is
alive</summary>
public bool IsAlive
{ get { return referance.IsAlive; } }

/// <summary>Compare WeakDelegates for equality</summary>
/// <param name="obj">Compare this to "obj"</param>
/// <returns>True if WeakDelegates are equivialent</returns>
public override bool Equals(object obj)
{
if(obj == null || GetType() != obj.GetType())
return false;
WeakDelegate d = (WeakDelegate)obj;
return ((this.referance.Target == d.referance.Target) &&
(this.methodName == d.methodName));
}

/// <summary>Get the hash code of this WeakReferance</summary>
/// <returns>Hash code</returns>
public override int GetHashCode()
{
return methodName.GetHashCode() + referance.Target.GetHashCode();
}

private string methodName;
private WeakReference referance;
}

/// <summary>Multicast Delegate which does not prevent garbage
collection</summary>
public class WeakMulticastDelegate
{
/// <summary>Call all methods referanced by this
WeakMulticastDelegate.
/// Also removes any delegates that point to dead objects</summary>
/// <param name="args">Arguments to pass all invoked methods</param>
public void InvokeAll(object[] args)
{
WeakDelegate current;
for(int i = 0; i < delegates.Count; i++)
{
current = delegates[i] as WeakDelegate;
if(current.IsAlive)
current.Invoke(args);
else
{
delegates.RemoveAt(i);
i--;
}
}
}

/// <summary>Add a WeakDelegate to the invokation list</summary>
/// <param name="d">WeakDelegate to add</param>
public void AddDelegate(WeakDelegate d)
{
delegates.Add(d);
}

/// <summary>Remove a WeakDelegate from the invokation
list</summary>
/// <param name="d">WeakDelegate to remove</param>
public void RemoveDelegate(WeakDelegate d)
{
delegates.Remove(d);
}

private ArrayList delegates = new ArrayList();
}
}