Wednesday 6 September 2017

Destructor in C#

Introduction
Destructors are used to destruct instances of classes.  In this article you will understand how different C# destructors are when compared to C++ destructors.

In C# you can never call them, the reason is one cannot destroy an object. So who has the control over the destructor (in C#)? it's the .NET frameworks Garbage Collector (GC).  

Indeed, if you look at the intermediate language (IL) generated for each .NET Framework instruction via ildasm.exe (Intermediate Language Disassembler), you'll find that the C# compiler emits the name ~Y (destructor in Listing 5.72 above) as Finalize. 

X's implicit call to base.Finalize is mysterious. In C++, destructors for derived objects destroy their base-class subobjects automatically. By contrast, C# finalizers don't intrinsically call other finalizers, including base-class finalizers. Nonetheless, you often want to finalize both a derived object and its base class in the same call. Furthermore, every C# class you write has exactly one base class, even if that base class is implicitly System.Object. 

When you exit the program, you can make the System.GC methods force the GC to schedule the implicit finalizer call, and then wait for that call to complete, as shown. 

System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); 

You can also call System.GC.SuppressFinalize to prevent the garbage collector from implicitly invoking the finalizer a second time. 

Do not directly call your base class Finalize method. It is called automatically from your destructor. 


Syntax of Destructor(~)~ ClassName()
using System;
namespace destructorex
{
    class Program    {
        ~Program() // destructor define         { 
           // clean up statement        }
    }
}

Characteristics of  Destructor
  • Destructors (~) cannot be defined in Structs.
  • Destructors (~) are only used with classes.
  • Destructor cannot be inherited or overloaded.
  • Destructor does not take modifiers or have parameters.
  • Destructor cannot be called. They are invoked automatically.
  • An instance becomes eligible for destruction when it is no longer possible for any code to use the instance.
  • The Programmer has no control over when destructor is called because this is determined by Garbage Collector.
  • Destructor is called when program exits.
  • Execution of the destructor for the instance may occur at any time after the instance becomes eligible for destruction.
  • Destructor implicitly calls Finalize on the base class of object.
Example 
 
The above given code is implicitly translated to the following code:

     protected override void Finalize() 
        {
            try            {
                // to clean conditions            }
            finally 
            {
                base.Finalize();
            }
       }

Explanation of code: Finalize() is called recursively for all instances in the inheritance chain, from most derived to least derived.

Garbage collector
  • Garbage collector  checks for objects that are no longer being used by application, if it treated an object eligible for destruction, it calls the destruction and reclaims the memory used to store  the object.
  • GC keeps tracks of all the objects and ensures that each object gets destroyed once.
  • GC ensures that objects, which are being referenced, are not destroyed.
  • GC destroys the objects only when necessary. Some situations of necessity are memory is exhausted or user explicitly calls System.GC.Collect() method.
Note Execution order: Base constructor is getting called first. In general, destructors are called in the reverse order of the constructor calls.  


Unmanaged Code:

[DllImport("kernel32.dll", SetLastError = true)]
   static extern IntPtr GetStdHandle(int nStdHandle); 

   [DllImport("kernel32.dll", SetLastError = true)]
   static extern bool WriteConsole(IntPtr hConsoleOutput, string lpBuffer,
          uint nNumberOfCharsToWrite, out uint lpNumberOfCharsWritten,
          IntPtr lpReserved);   

   [DllImport("kernel32.dll", SetLastError = true)]
   static extern bool CloseHandle(IntPtr handle); 

Program of Execution order class First{
    ~First()
    {
        System.Console.WriteLine("First's destructor is called");
    }
}
class Second : First{
    ~Second()
    {
        System.Console.WriteLine("Second's destructor is called");
    }
}
class Third : Second{
    ~Third()
    {
        System.Console.WriteLine("Third's destructor is called");
    }
}
class TestDestructors{
    static void Main()
    {
        Third t = new Third();
    }
}
Output

dee.gif
ILDASM command :

2.gif
Note Execution order base constructor is getting called first. In general, destructors are called in the reverse order of the constructor calls.  

Some Useful Points
  1. When your application encapsulates unmanaged resources such as:
     
    • Windows
    • Files
    • Network connections
    you should use destructors to free those resources.
     
  2. When an object is eligible  for destruction, the garbage collector runs the Finalize () method of that object.
     
  3. Empty destructors should not be usedReason - When a class contains a destructor , an entry is created in the finalize queue. if the destructor is empty , this just causes a needless loss of performance.
     
  4. Explicit release of resourcesSuppose  an application uses a costly external resources, then a  way to explicitly release the resource before the garbage collector frees the object.
    IDisposable Interface -  Defines a method to release allocated resources.
                                       Namespace : System
                                       Assembly : mscorlib (in mscorlib.dll) 

No comments:

Post a Comment