C# and destructors

Discussion in 'C#' started by shabbir, Sep 25, 2006.

  1. shabbir

    shabbir Administrator Staff Member

    Joined:
    Jul 12, 2004
    Messages:
    15,375
    Likes Received:
    388
    Trophy Points:
    83

    Background



    In C#, programmer has no control on when the destructor is going to be executed because this is determined by the Garbage Collector. The garbage collector checks for objects that are no longer used by the application and calls the destructors of all the objects and reclaims the memory of the objects. The process of calling of destructor is totally asynchronous with the program flow and so there could be some errors to make the program synchronous. Say you have a file class for the file operations and the file is kept open for the operations that are performed on the file and when the object is no more needed you close the file. Normally you open the file in the constructor and close the file in the destructor but if you are not sure when the destructor will be called you should not be continuing such practice.

    Lets start with an example



    Try running the following program
    Code:
    class Base
    { 
        public Base()
        {
            Console.WriteLine("Base class constructor");
        }
        ~Base()
        {
            Console.WriteLine("Base class destructor");
        }
    }
    
    class DeriveLevel1 : Base
    {
        public DeriveLevel1()
        {
            Console.WriteLine("DeriveLevel1 class constructor");
        }
        ~DeriveLevel1()
        {
            Console.WriteLine("DeriveLevel1 class destructor");
        }
    }
    
    class DeriveLevel2 : DeriveLevel1
    {
        public DeriveLevel2()
        {
            Console.WriteLine("DeriveLevel2 class constructor");
        }
        ~DeriveLevel2()
        {
            Console.WriteLine("DeriveLevel2 class destructor");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            DeriveLevel2 dl2 = new DeriveLevel2();
            dl2 = null;
    
            Console.Read();
        }
    }
    You will not see the destruction code on the screen but when the program ends it will flash but it will not be noticibale. This is because Garbage collector destroys the object when the program ends or when it thinks that the object is no more needed by any processes running. You can forcibly call the destructor by initiating the Garbage collector. Try adding GC.Collect(); after the assignment of the null to dl2 and you will see the destructors output as well.

    The above method is not the best method because this might not be the right time to initiate the garbage collector and when the garbage collector runs it not only frees up your desired objects but some objects that you don't need cleaning up right at this moment.

    The other method is Implement IDisposable interface in your class and override the Dispose method and make all the cleanup in the Dispose method. Also you need to call the Dispose method from the destructor for cleanup.

    Now try running the following program.
    Code:
    class Base
    { 
        public Base()
        {
            Console.WriteLine("Base class constructor");
        }
        ~Base()
        {
            Console.WriteLine("Base class destructor");
        }
    }
    
    class DeriveLevel1 : Base
    {
        public DeriveLevel1()
        {
            Console.WriteLine("DeriveLevel1 class constructor");
        }
        ~DeriveLevel1()
        {
            Console.WriteLine("DeriveLevel1 class destructor");
        }
    }
    
    class DeriveLevel2 : DeriveLevel1, IDisposable
    {
        public DeriveLevel2()
        {
            Console.WriteLine("DeriveLevel2 class constructor");
        }
        ~DeriveLevel2()
        {
            Console.WriteLine("DeriveLevel2 class destructor");
        }
        public void Func()
        {
            Console.WriteLine("DeriveLevel2 class Func");
        }
        public void Dispose()
        {
            Console.WriteLine("DeriveLevel2 class Dispose");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            using( DeriveLevel2 dl2 = new DeriveLevel2())
            {
                dl2.Func();
            }
            Console.Read();
        }
    }
    Its a good practice to call the GC.SupressFinalize(this) as it tells the Garbage Collector that there is no need to call its destructor because we have already done the clean up.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice