In non-garbage collected languages like C++, programmers must take care of memory and resource management, you know exactly when your objects are destroyed, implicitly (scope rules) or explicitly (object deletion). The counterpart is that working with pointers commonly leads to memory leaks and resources never freed. Opposed to this, the .NET environment implements a garbage collector that automates memory management and handles unused object destruction, making the programmer's life simpler. Objects are not destroyed when they are out of scope, and you can’t destroy them explicitly. It’s the GC’s job to destroy them and free the memory used, this is called “collecting” and it is done under certain circumstances that won’t be explained here. This means that the GC collects when needed, and you have no control of the destruction of your objects.
Therefore, there are no special considerations to take when writing a class that doesn't make use of resources. But when your class holds a critical resource, you must release, you just can't rely on the GC because you can’t determine when it will run. The GC, upon collection, calls the finalizer of the object (in C#, the finalizer is the object destructor), thus, this is not a good place to release the resources owned by an object. In the .NET class library, the garbage collector is implemented as
System.GC in the assembly
There is an interface in .NET you must implement to "mark" your class in order to provide a mechanism to release resources. This interface is
IDisposable (its full name is
System.IDisposable and can be found in assembly
mscorlib). And it has only one method you must implement:
Dispose(). This method does the cleaning work in your class. The destructor should call
Dispose() to ensure a clean exit in case you forgot to explicitly call it, but not if it has already been called. A proposed implementation is:
public class A : IDisposable
protected bool disposed = false;
public void doSomething()
throw new ObjectDisposedException("object's name");
public void Dispose()
protected virtual void Dispose(bool disposing)
disposed = true;
A virtual method
Dispose(bool) manages resource deallocation for both managed and unmanaged resources.
disposing is a parameter to tell who called the method.
Dispose() will call
Dispose(true) and the destructor will call
Dispose(false). When instantiating class
A, all resource acquisition is made in the constructor, and when we are done with the object, we need to call
Dispose(true) from the public method
Dispose() to release all (both managed and unmanaged) resources. The destructor, called by the GC, also calls
Dispose(false) to clean unmanaged resources to ensure there are no leaks in our application. Calling
GC.SuppressFinalize() tells the GC not to call the object's destructor, for it just does what we have already done.
Dispose(bool disposing) is declared as
virtual so our derived classes can call it.
disposed is a flag to avoid calling
Dispose() more than once and to avoid using a released resource, an
ObjectDisposedException is thrown if this happens. Note that this implementation is not thread-safe, race conditions can happen.
The need to implement
Dispose(bool) arises because an object may hold both managed objects that need to be disposed and unmanaged resources. So, if you call
Dispose(true), you take care of all resources owned and that's all, but if you don't, the GC will take care and the owner object should no longer call
Dispose(true) on each of the owned managed objects because they may be already finalized. But you must always clean unmanaged resources by calling
Derived classes can easily extend this implementation:
public class B : A
protected override void Dispose(bool disposing)
Creating an instance of
B's constructor, which in turn calls
A's default constructor before exiting.
B's destructor does nothing, it only follows the destruction chain calling
A's destructor (in fact, we can obviate it, and when the GC claims the object, it will call
A's destructor because it's inherited by
B). Anyway, we reach
A's destructor where
Dispose(false) is called. But
Dispose(bool) is overridden, it was declared as
A so the right
Dispose(bool) in the right class is called in
A's destructor. If it weren't declared as
A.Dispose(bool) would be called thereby not calling
B.Dispose(bool) and never releasing
B's unmanaged resources.
Taking a closer look to our example, the output of Ildasm.exe says:
~A() is translated as
A.Finalize() when compiled to IL).
.method family hidebysig virtual instance void Finalize() cil managed
IL_0002: callvirt instance void Test.A::Dispose(bool)
IL_0007: leave.s IL_0010
IL_000a: call instance void [mscorlib]System.Object::Finalize()
} IL_0010: ret
The compiler automatically generates code to control exceptions, it puts our code inside a
finally block ensuring chain destruction by calling the base class destructor inside the
finally block. Also, if the virtual call to
Dispose(bool) throws an exception and it is not handled, the program continues with the execution flow. If exceptions are not properly handled inside every
Dispose() method, resource leaks can occur.
The using statement
C# has the
using statement that allows you to acquire one or multiple resources, use them in a block, and automatically call
Dispose() in each of them.
public class AppClass
public static void Main()
using (B a = new B())
This block of code translates to IL in the following manner:
.method public hidebysig static void Main() cil managed
.locals init ( class Test.B a)
IL_0000: newobj instance void Test.B::.ctor()
IL_0007: callvirt instance string [mscorlib]System.Object::ToString()
IL_000c: call void [mscorlib]System.Console::WriteLine(string)
IL_0011: leave.s IL_001d
IL_0014: brfalse.s IL_001c
IL_0017: callvirt instance void [mscorlib]System.IDisposable::Dispose()
} IL_001d: ret
That is the same as coding:
B a = new B();
if (a != null)
using also allows declaring more than one identifier of the same type:
using (B a1 = new B(), a2 = new B())
using statement executes the statement block disposing the objects when the end of the statement is reached or when an exception is thrown.
The non-deterministic object destruction provided by the GC forces us to take special care when working with objects wrapping resources:
IDisposable provides the contract a class must implement for correct resource use.
Dispose(true) to release all resources and tells the GC not to call the destructor.
virtual and calling the inherited method from the derived classes.
Dispose() invocation through the
Dispose(false) in the destructor. Just in case...
Dispose() more than once shouldn’t do anything.
- Making use of a disposed object should throw