Garbage Collection in .NET – Part 4/4

Table of contents of Part 1

Table of contents of Part 2

Table of contents of Part 3

Table of contents of Part 4

 

Dispose Pattern

The Dispose Pattern is a software design pattern that is used for resource management. Compared to a Finalizer, it’s an improved technique to release native resources. As mentioned in the previous chapter, one of the drawbacks of the Finalize method is that it is not possible to control when it will be called. In contrast to a Finalize method, the Dispose Pattern provides release control over native resources. It is possible to control and call the Dispose method deterministically.

In cases when the Dispose Pattern and the Finalize method will be used at the same time, there are a few critical points that must be considered.

Figure-14 shows the implementation of the Dispose Pattern with a Finalize method. It can be divided into four sections.

Control flag

In line 3, the control flag is used to prevent redundant calls to Dispose() method.

Finalize method

In line 5. The key point here is the cleaning up of the native resources is no longer performed here. Instead, in Dispose() method they must be performed. Here, the only thing that must be done is to call the overload of the Dispose() method with the false flag. The reason for that is, that the Garbage Collector will clean up all managed resources during the finalization process. That’s why it’s important not to interact with managed objects if the Dispose() method is called with false. When the Finalize method is not needed then the Finalize method (~MyClass()) can simply be removed. At the same time, the call to the GC.SuppressFinalize() method at line 14 must be removed.

Implementation of IDisposable interface

Implementation of the Dispose Pattern with Finalize method
Figure 14: Implementation of the Dispose Pattern with Finalize method

In line 10, similar to the Finalize method, the overload of Dispose() must be called here with true. Since this method is called by the user deterministically, the managed resources must be released. This is why the overload of the Dispose() method is called with true. In addition to that, since the Finalize method is implemented, the GC.SuppressFinalize() method must be called to suppress unnecessary calls to the finalizer. This method requests the CLR not to call the finalizer for this specific object.

Overload of the Dispose method

In line 17, the method where the real clean-up occurs. All method logic is wrapped by an if (isDisposed) block which is controlled by the controller flag of the Dispose pattern. With the help of this, additional calls to Dispose() method after the first call are ignored. So it is safe to call the Dispose() method of an object multiple times.

This method consists of three sections. The first one is another if block whose condition is dependent on the value of parameter disposing. This value is set to false if the method is called from the Finalize method which means skipping cleaning up the managed objects. The value is set to true if the method is called from the Dispose() method which means all managed objects will be cleaned up. The second part of the method is the section where native resources are released and the control flag is set to true to prevent further calls of Dispose() method and the last part is a call to the Dispose() method of the base class if the class is inherited from a base class that implements an IDisposable interface. This call isn’t needed unless the class is inherited from a base class.

The Dispose pattern is the safe and the deterministic way of the Finalization.

References

 

For more Software Engineering related topics go to Software Engineering | Method Park by UL.