- When Is Memory Released?
- IDisposable and the Dispose Design Pattern
- The C# "using" Syntax
- Conclusion
- References
IDisposable and the Dispose Design Pattern
As it turns out, the .NET development team thought of all this, and created an interface, IDisposable, that describes it. They also created the Dispose design pattern that provides a suggested implementation. Finally, they added support for the Dispose design pattern to the C# language in the form of the using syntax. There's no requirement that your objects implement IDisposable and the Dispose design pattern, but since you need some way of releasing unmanaged resources, you might as well use the system that the .NET development team formalized and used throughout the Framework classes.
The .NET SDK documentation includes a detailed description of the Dispose design pattern. Rather than repeat everything presented in that article, I'll just cover the highlights and show how to implement IDisposable in the CoolThing class.
The IDisposable interface consists of a single method: Dispose(). This method is used to free, release, or reset a resource that the implementing class uses. With the addition of the code shown in Listing 4, the CoolThing class implements the IDisposable interface. But it doesn't implement the Dispose design pattern as described in the SDK documentation. For that, it needs a little bit more logic.
When you implement the Dispose design pattern, you have to take into account two different scenarios in which the object's resources are deallocated: when a program calls the Dispose() method directly, and when the garbage collector calls the object's finalizer. If the object's finalizer is called, the object cannot reference other objects, because those objects might no longer be valid. That's the reason for the overridden Dispose(bool) method: The Boolean parameter controls whether managed resources (other objects) are cleaned up. The CoolThing2 class in Listing 5 provides a full implementation of the Dispose design pattern.
Listing 5 CoolThing2.cs
using System; namespace AllocExample2 { public class CoolThing2: IDisposable { private static readonly int MaxCoolThings = 3; private static int ThingsAllocated = 0; private int thingNumber; // disposed variable tells if the resources have been released private bool disposed = false; public int ThingNumber { get { return thingNumber; } } public CoolThing2(int tn) { if (ThingsAllocated == MaxCoolThings) { throw new ApplicationException("No free CoolThings"); } thingNumber = tn; Console.WriteLine("Thing {0} allocated", thingNumber); ++ThingsAllocated; } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // release managed resources --ThingsAllocated; } // release any unmanaged resources } disposed = true; } ~CoolThing2() { if (!disposed) Dispose(false); Console.WriteLine("Thing {0} released", thingNumber); } } }