This came up from a case where I was trying to see what happened at the exit of a using block with event handlers that were still registered and if they'd prevent garbage collection. I put together a test program to try it out though, and I found a strange behaviour. It seems that if I have an object declared as part of a using statement, the object isn't finalized. Here's my sample code:
using System; using System.Threading; namespace UsingTest { //class that just implements and fires an event forever class EventTest: IDisposable { public EventTest() { m_timer = new Timer((s) => { if (TestEvent != null) TestEvent(null, new EventArgs()); }, null, 0, 1000); } ~EventTest() { Console.WriteLine("Destructor called"); } private System.Threading.Timer m_timer; public void FireEvent() { TestEvent(null, new EventArgs()); } public event EventHandler TestEvent; public void Dispose() { m_timer.Dispose(); Console.WriteLine("Dispose called"); } } class Program { private static void Case1() { EventTest t = new EventTest(); EventHandler eh = new EventHandler((sndr, ea) => { Console.WriteLine("Got Event"); }); t.TestEvent += eh; Console.ReadLine(); t.TestEvent -= eh; t.Dispose(); t = null; Console.WriteLine("Garbage collection"); GC.Collect(2, GCCollectionMode.Forced); } private static void Case2() { using (EventTest t = new EventTest()) { EventHandler eh = new EventHandler((sndr, ea) => { Console.WriteLine("Got Event"); }); t.TestEvent += eh; Console.ReadLine(); t.TestEvent -= eh; } Console.WriteLine("Garbage collection"); GC.Collect(2, GCCollectionMode.Forced); } static void Main(string[] args) { Case1(); Console.ReadLine(); } } }
As you can see, it's pretty basic-create an object that fires an event, subscribe to the event handler, and then unsubscribe and destroy the object. If I called Case1(), you'll notice that there's no using-I explicitly create the object, use it, dispose it, null it out, and then force a garbage collect. This correctly calls both Dispose and the Finalizer. Now, Case2 does almost exactly the same thing, except with a using directive, and this time, Dispose gets called, but the finalizer does not get called until the program exits, even though garbage collection has been forced. Even though dispose can free unmanaged resources, this means that any managed resources that are being held by the object are not garbage collected when the using block is left, since the finalizer has not been called, correct?
So, I suppose the question is, is this normal? I looked at the msdn topic on the using statement, and it says this just compiles down to a dispose call in the finally block, but shouldn't this also call the managed finalizer when the variable is out of scope?
Looking forward to figuring this one out-even after this long, I still run across surprising stuff like this in C#.