Straight to the code
class Program
{
private static WeakReference<EventHandler<EventArgs>> _noClosure;
private static WeakReference<EventHandler<EventArgs>> _closure;
static void Main(string[] args)
{
Init();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
EventHandler<EventArgs> target;
Console.WriteLine(_closure.TryGetTarget(out target));
Console.WriteLine(_noClosure.TryGetTarget(out target));
}
class C { public void Go() { } }
private static void Init()
{
_noClosure = new WeakReference<EventHandler<EventArgs>>((sender, args) =>
{
});
var s = new C();
_closure = new WeakReference<EventHandler<EventArgs>>((sender, args) =>
{
s.Go();
});
}
}
The output I get from this code is
False
True
How on earth is this possible?
P.S. I came into this while trying to figure out how WeakEventManager
works.
The compiler will cache the _noClosure
delegate in a static field, and reuse it every time you call Init
. The exact same instance can be reused every time.
Compare that with _closure
, which closes over a new instance of C()
on each call to Init()
- that can't be cached.
The caching of _noClosure
means that there's a strong reference (the field) to the delegate, so it can't be garbage collected.
If you run ildasm
on your application, you can see all of this in action.
See more on this question at Stackoverflow