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!
2 comments:
Interesting, 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.
Post a Comment