Implementing Deterministic Destruction in C#
articlesbyJosephMayo
Implementing Deterministic Destruction in C#
In languages like C++, objects go out of scope or are deleted and their destructors are executed immediately. This is known as deterministic destruction. A significant difference with C# is that there is no way to know when an object’s destructor will be called or if the destructor will ever be called.
The reasons have to do with the C# garbage collector. Regardless of the reason, one problem remains: How do you guarantee that system resources will be released when the object is no longer needed? The answer is the C# using statement, as shown in the following code:
using System; public class MyResouceHolder : IDisposable { // initialize and work with resources... // release resources public void Dispose() { // code to release some resource... Console.WriteLine("MyResouceHolder.Dispose() called"); // don’t invoke destructor GC.SuppressFinalize(this); } // destructor ~MyResouceHolder() { Dispose(); } } class MyMainApp { static void Main(string[] args) { MyResouceHolder resourceHolder = new MyResouceHolder(); // call Dispose() when done using (resourceHolder) { // code using resourceHolder... Console.WriteLine("Before leaving using statement."); } Console.WriteLine("After leaving using statement."); } }
Here's the output:
Before leaving using statement. MyResouceHolder.Dispose() called After leaving using statement.
The using statement in Main() holds a reference to resourceHolder. Some programming statements are executed within the body and a comment is printed to the console prior to exiting the using statement.
Upon exiting the using statement, resourceHolder’s Dispose() method is executed, releasing resources as necessary. Prior to leaving the Dispose() method, the GC.SuppressFinalize() method is invoked, informing the garbage collector to not invoke this object’s destructor. At this point, we don’t want the garbage collector to call the destructor. If you’ll notice, the destructor calls the Dispose() method to release resources and calling Dispose() twice could yield some strange results.
The reason the using statement knows to call the Dispose() method is because the MyResourceHolder class implements the IDisposable interface, which contains a Dispose() method specification. If MyResouceHolder did not implement IDisposable, the compiler would have generated an error because the using statement can only contain an object that implements the IDisposable interface.