Destructors

Destructors in C# are special methods that clean up resources held by a class instance before the object is destroyed. They are particularly useful for releasing unmanaged resources, such as file handles, database connections, or memory allocated through unmanaged code. Destructors provide a way to implement deterministic finalization logic in C#.

Characteristics of Destructors

  • Naming Conventions: A destructor shares its name with the class, but it is preceded by a tilde (~) symbol.
  • Parameters: Destructors do not accept parameters and cannot be overloaded.
  • Access Modifiers: Destructors do not use access modifiers. They are always treated as protected and internal.
  • Automatic Invocation: When an object is no longer accessible, the garbage collector automatically calls the destructor.
  • Single Instance Limitation: Each class is allowed to have only one destructor.

Example

using System;

class ResourceHolder
{
  // Field to simulate an unmanaged resource
  private IntPtr unmanagedResource;
 
// Constructor to allocate the unmanaged resource
  public ResourceHolder()
  {
      // Simulate allocation of an unmanaged resource
      unmanagedResource = new IntPtr(54321);
      Console.WriteLine("Resource allocated.");
  }

    // Destructor to clean up the unmanaged resource
  ~ResourceHolder()
  {
      // Simulate releasing the unmanaged resource
      Console.WriteLine("Resource released.");
  }

    // Method to use the resource
  public void UseResource()
  {
      if (unmanagedResource != IntPtr.Zero)
      {
          Console.WriteLine("Using resource.");
      }
      else
      {
          Console.WriteLine("Resource not available.");
      }
  }
}

class Program
{
  static void Main()
  {
      // Create an instance of ResourceHolder
      ResourceHolder holder = new ResourceHolder();

        // Use the resource
      holder.UseResource();

        // Forcing garbage collection for demonstration purposes (not recommended in real applications)
      holder = null;
      GC.Collect();
      GC.WaitForPendingFinalizers();
  }
}

Explanation of the Example

Class Definition:
  • We define a ‘ResourceHolder‘ class that simulates managing an unmanaged resource using the ‘IntPtr‘ type.
Constructor:
  • The constructor initializes the ‘unmanagedResource‘ field with a simulated value and prints a message indicating that the resource has been allocated.
Destructor:
  • The destructor is defined using the ‘~ResourceHolder‘ syntax. It simulates releasing the unmanaged resource and prints a message indicating that the resource has been released.
Method:
  • The ‘UseResource‘ method checks if the resource is available and prints a message indicating that the resource is being used.
Main Method:
  • We create an instance of the ‘ResourceHolder‘ class, which triggers the constructor to allocate the resource.
  • We then call the ‘UseResource‘ method to demonstrate how to use the resource.
  • After that, we set the holder object to ‘null‘ and force garbage collection by calling ‘GC.Collect()‘ and ‘GC.WaitForPendingFinalizers()‘ to illustrate the destructor in action. (Please note that forcing garbage collection is not recommended in real applications.)

Key Concepts

Garbage Collection: The .NET runtime offers automatic memory management through garbage collection. When an object is no longer accessible, the garbage collector invokes its destructor.

Resource Management: Destructors are helpful for cleaning up unmanaged resources that the garbage collector does not manage. However, it is generally better to use the IDisposable interface along with the using statement for deterministic disposal of resources.

Deterministic Finalization: Although destructors provide a means to release resources, they do not ensure timely execution. For resources that require deterministic cleanup, it’s important to implement the IDisposable interface and use the Dispose method.

Post a comment

Leave a Comment

Scroll to Top