I came across a problem this week. I was needing a weak delegate to handle a situation where I have a ListBox and I want it to listen to a property changed on a selected ListBoxItem. This situation need to have a weak delegate because if the ListBoxItem is kept referenced, I want to let the ListBox to be garbage collected.
This is how I have implemented the WeakEventHandler. I thought it was a good implementation because it also supports the anonymous methods even if they are closure.
WeakEventHandler
The WeakEventHandler is a thin class inheriting the WeakHandler<T> and provinding a closure delegate in the CreateHandler.
public sealed class WeakEventHandler : WeakHandler<EventHandler>
{
public WeakEventHandler(EventHandler handler)
: base(handler)
{
}
protected override EventHandler CreateHandler(WeakReference weakReference)
{
return (sender, e) =>
{
var h = (EventHandler)weakReference.Target;
if (h != null)
h(sender, e);
};
}
}
The WeakHandler base class
The WeakHandler is the based class for all delegate type. It provide automatic translation to a weak delegate build by the CreateHandler.
public abstract class WeakHandler<T> where T : class
{
private T handler;
private T implicitHandler;
protected WeakHandler(T handler)
{
if (handler == null)
throw new ArgumentNullException("handler");
if (!(handler is Delegate))
{
throw new InvalidOperationException();
}
this.handler = handler;
}
protected abstract T CreateHandler(WeakReference weakReference);
public static implicit operator T(WeakHandler<T> weakHandler)
{
if (weakHandler == null)
return null;
if (weakHandler.implicitHandler == null)
{
lock (weakHandler.handler)
{
if (weakHandler.implicitHandler == null)
{
var ih = weakHandler.CreateHandler(new WeakReference(weakHandler.handler));
Thread.MemoryBarrier();
weakHandler.implicitHandler = ih;
}
}
}
return weakHandler.implicitHandler;
}
}
How to use it
You can use the WeakEventHandler simply as if you where the EventHandler provided by the framework:
Form f = new Form();
f.SizeChanged += new WeakEventHandler(delegate(object sender, EventArgs e)
{
Console.WriteLine("Form changed.");
});
Where are we?
We saw how to implement and reuse weak event handler. This event is very easy to create and reuse.
Happy Programming!
This comment has been removed by the author.
ReplyDeleteInteresting, but with this solution, you still keep a strong ref to the WeakEventHandler instance which won't be GC'ed. This is definitely better that keeping a strong ref to the potential bigger object that normally subscribes directly to the event. I guess we still need a real solution for this pattern, but this one is much better than what I've seen so far.
ReplyDelete