Finalizers

Create destructors for user-defined types.

Introduction

Most objects used in C# programs are managed code. Such objects are managed by the CLR and are easily cleaned by the garbage collector. There are also objects that involve unmanaged resources, however (connections to files, databases, network connections, and so on). These unmanaged objects access the operating system APIs. The garbage collector can handle managed objects, but it doesn’t know how to dispose of unmanaged resources. In these cases, we must implement the cleanup means by ourselves.

The release of unmanaged resources implies the implementation of one of two mechanisms: creation of a destructor or implementation of the IDisposable interface

Destructors

Constructors are used to create an instance of a class. Destructors, on the other hand, contain instructions on what happens when an instance gets destroyed (by the garbage collector). Destructors:

  • Can only be defined in classes.
  • Can’t have access modifiers or parameters.
  • Can’t be inherited or overridden.

Note: Each class can only have one destructor.

A destructor method has a class name (like a constructor) preceded by a tilde sign (~):

class Car
{
	// Constructor
	public Car()
	{
	}

	// Destructor
	~Car()
	{
		// Instructions to release unmanaged resources
	}
}

When compiled, our ~Car() destructor is converted to a code similar to the following:

protected override void Finalize()
{
	try
	{
		// Instructions to release unmanaged resources
	}
	finally
	{
		base.Finalize();
	}
} 

The garbage collector calls the Finalize() method when removing the object from memory. We can’t override the Finalize() method manually, so we must create a destructor instead. The Finalize() method is defined in the System.Object class.

Call the destructor

For demonstration purposes, let’s put a simple Console.WriteLine() statement inside the destructor. Observe when the destructor is called:

Get hands-on with 1200+ tech skills courses.