A destructor is a special method that is called when an object is being destroyed or garbage collected. It is used to perform cleanup operations, such as releasing resources or freeing memory that the object may be holding onto. Destructors are particularly useful for managing unmanaged resources, such as file handles or database connections.
Key Features of Destructors
- Name: A destructor has the same name as the class but is preceded by a tilde (
~
). - No Parameters: Destructors do not take parameters and cannot be overloaded.
- No Return Type: Destructors do not have a return type.
- Automatic Invocation: The .NET garbage collector automatically calls the destructor when the object is no longer in use.
- Finalization: The destructor is part of the finalization process. It allows you to clean up resources before the object is removed from memory.
Syntax of a Destructor
csharp1class ClassName 2{ 3 ~ClassName() 4 { 5 // Cleanup code here 6 } 7}
Example of a Destructor
Here’s an example that demonstrates how to use a destructor in a class that manages unmanaged resources.
Example 1: Basic Destructor
csharp1using System; 2 3public class Resource 4{ 5 // Simulating an unmanaged resource 6 private IntPtr unmanagedResource; 7 8 public Resource() 9 { 10 // Allocate unmanaged resource 11 unmanagedResource = Marshal.AllocHGlobal(100); // Allocate 100 bytes 12 Console.WriteLine("Unmanaged resource allocated."); 13 } 14 15 ~Resource() 16 { 17 // Cleanup code 18 if (unmanagedResource != IntPtr.Zero) 19 { 20 Marshal.FreeHGlobal(unmanagedResource); // Free the allocated memory 21 Console.WriteLine("Unmanaged resource freed."); 22 } 23 } 24} 25 26// Usage 27public class Program 28{ 29 public static void Main() 30 { 31 Resource res = new Resource(); 32 // The destructor will be called when the object goes out of scope 33 // or when the garbage collector runs. 34 } 35}
Important Considerations
Timing of Destructor Execution: The exact timing of when a destructor is called is non-deterministic. The garbage collector runs at its own discretion, so you cannot predict when the destructor will be executed.
Finalization Queue: When an object with a destructor is no longer reachable, it is placed in a finalization queue. The garbage collector will call the destructor before reclaiming the memory.
Performance Impact: Having destructors can impact performance because objects with destructors require an extra pass by the garbage collector to finalize them.
Use of IDisposable: It is generally recommended to implement the
IDisposable
interface and provide aDispose
method for deterministic cleanup of resources, especially when dealing with unmanaged resources. Destructors should be used as a fallback for cleanup whenDispose
is not called.
Example of Destructor with IDisposable
Here’s an example that combines a destructor with the IDisposable
interface to manage resources more effectively.
csharp1using System; 2using System.Runtime.InteropServices; 3 4public class Resource : IDisposable 5{ 6 private IntPtr unmanagedResource; 7 private bool disposed = false; // To detect redundant calls 8 9 public Resource() 10 { 11 // Allocate unmanaged resource 12 unmanagedResource = Marshal.AllocHGlobal(100); // Allocate 100 bytes 13 Console.WriteLine("Unmanaged resource allocated."); 14 } 15 16 // Implement IDisposable 17 public void Dispose() 18 { 19 Dispose(true); 20 GC.SuppressFinalize(this); // Suppress finalization 21 } 22 23 protected virtual void Dispose(bool disposing) 24 { 25 if (!disposed) 26 { 27 if (unmanagedResource != IntPtr.Zero) 28 { 29 Marshal.FreeHGlobal(unmanagedResource); // Free the allocated memory 30 unmanagedResource = IntPtr.Zero; 31 Console.WriteLine("Unmanaged resource freed."); 32 } 33 34 disposed = true; // Mark as disposed 35 } 36 } 37 38 ~Resource() 39 { 40 // Finalizer calls Dispose(false) 41 Dispose(false); 42 } 43} 44 45// Usage 46public class Program 47{ 48 public static void Main() 49 { 50 using (Resource res = new Resource()) 51 { 52 // Use the resource 53 } // Dispose will be called automatically here 54 } 55}
Explanation of the Example
IDisposable Interface: The class implements
IDisposable
, which provides aDispose
method for manual resource management.Dispose Method: The
Dispose
method is called to free unmanaged resources. It also sets a flag (disposed
) to prevent multiple calls.Finalizer: The destructor (finalizer) calls
Dispose(false)
, ensuring that unmanaged resources are cleaned up if theDispose
method is not called.Using Statement: The
using
statement ensures thatDispose