Destructor in C#

来源:互联网 发布:手机免费代理软件 编辑:程序博客网 时间:2024/06/11 05:42
Author Date Of Submission User Level Neeraj Saluja 05/12/2004 Beginner
The article introduces destructors and how they are implemented in C#. Let us start by defining destructors in simple terms.

Destructor is method in the class which is aimed to release the resources that the instance of the class has acquired. This method is called by CLR when the instance of the class is getting destructed.

Since this method is executed at the time of destruction of the instance of the class, it is but obvious that it is meant for releasing the resources acquired by the objects as the instance will be no more in existence after executing this method. This does not mean that developer cannot write any other code - he/she can. The complete onus is on developer of whatever is written in that method. It is simply like any other method written with the specific aim. The developer could use it to log some information using this method so it all depends on the developer what to use it for.

How a destructor looks like, here is the sample:
 
public class myclass
{
        public myclass()
        {
                  // This is the constructor method of myclass.
        }

       ~myclass()
        {
                  // This is the destructor method of myclass.
        }
}

Few things to note here, before we get into details:

1. Destructor does not have access modifiers like public, private etc.
2. The destructor is like any other member method. The code could aim to anything, but the basic intention of this method is the release of the memory.
3. Destructors are called automatically by CLR, and to be more specific garbage collector; the developer cannot call them explicitly.
4. Overloaded destructor is not possible. One class can thus have at the most one destructor which is parameter less.
5. Destructors cannot be inherited.

Destructors in Inheritance scenario

Let us now see what happens when the classes with the destructors are involved in inheritance. Let us see this thing by an example. Have a look at the following console application:

// Neeraj Saluja [neeraj_saluja@indiatimes.com]
// Console Application to show behavior of Destructors in Inheritance.
using System;

namespace DestructorsExample
{

      ///
      /// The base class for Class2
      ///

      class Class1
      {
             ~Class1()
             {
                    Console.WriteLine("Destructor of Class1");
             }
      }
      ///
      /// Class2 inherting Class1
      ///

      class Class2 : Class1
      {
             ~Class2()
             {
                    Console.WriteLine("Destructor of Class2");
             }
      }
      ///
      /// MainClass.
      ///

      class MainClass
      {
             ///
             /// The main entry point for the application.
             ///

             [STAThread]
             static void Main(string[] args)
            {
                    Class2 objClass2 = new Class2();
            }
      }
}

What do you think should be the sequence of execution of destructors here ? Here is the output:

      Destructor of Class2
      Destructor of Class1

The thing that should be noted here is, we don抰 know when the destructor will be called but we always know in what sequence these executes when it comes to inheritance.

What抯 happening Internally
Let us now see how .Net is handling destructor. When you write a destructor, the compiler internally calls the Finalize() method of Object class after executing your destructor code. Let us look at the MSIL code of the Finalize method of class2:

.method family hidebysig virtual instance void
Finalize() cil managed
{
 // Code size 20 (0x14)
 .maxstack 1
 .try
 {
  IL_0000: ldstr "Destructor of Class2"
  IL_0005: call void [mscorlib]System.Console::WriteLine(string)
  IL_000a: leave.s IL_0013
 } // end .try
 finally
 {
  IL_000c: ldarg.0
  IL_000d: call instance void DestructorsExample.Class1::Finalize()
  IL_0012: endfinally
 } // end handler
 IL_0013: ret
} // end of method Class2::Finalize

You can get the above look by using the tool ildasm.exe.

Note that it first executes the destructor of the current class in the try block followed by the destructor of base class in the finally block.

If the class does not posses any destructor, the complete memory management is done by garbage collector. The garbage collector is designed to take care of release of memory of objects of each class. If you provide the destructor to the class, the destructor gets executed when the object destructs plus when the garbage collector takes it for cleaning. So it means by default your object of the class will undergo cleaning of resources twice. Well, you can tell the garbage collector to ignore the object of your class for clean up process. To do so, write the statement,  System.GC.SuppressFinalize in your destructor code. For further reference on methods of GC you can refer to MSDN.

Destructors FAQs

1. When should one write the destructor and when not?
 
The basic aim of destructor is to release the resources and memory held by the object. In    general you should not be worried about memory management as garbage collector takes cares of it in a beautiful way.

    However, when your class holds some unmanaged resources like files, network connection etc then you should use destructor. Also, when expensive external resources (though managed) are involved then also it is recommended to have destructor rather than waiting for garbage collector to do it.

2. Classes and Structs both have methods, can we have destructor for the Structs too?
No. Structs can not have destructor. Destructor is specifically meant for classes.

3. Can I force the garbage collector to release memory?
Yes, you can, using the syntax System.GC.Collect method. It is the overloaded method. But be sure of its implications before using this syntax ?it can lead to a performance issue. It is because when you are asking garbage collector to release the memory, it will try to release the memory in its own mechanism taking the entire memory into consideration, which could be resource consuming at that moment of time.

4. Can I have both the destructor and overloaded Finalize method in my class?
    
Logically speaking it is not required. Anyway, if somebody tries to write both then one will get the compile time error similar to this : 揅lass 'DestructorsExample.Class2' already defines a member called 'Finalize' with the same parameter types? This is because destructors are ultimately converted into Finalize method.

5. Where is this Finalize method came from ?I haven抰 inherited System.Object class?
The master base of all the classes is the System.Object class. And if you do not provide any class for inheritance the compiler automatically inherits the System.Object class for your class. So each class knowingly or unknowingly inherits this class.

6. What happens if the code inside the destructor raises an exception?
The CLR runtime ignores that exception and moves further. Say for example if your Class2   destructor looks something like this :

~Class2()
{
Console.WriteLine("Destructor of Class2");
System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection("some wrong
connection string here");
}

Then the output of the above program would something like this:

Destructor of Class2

Unhandled Exception: System.ArgumentException: Expected '=' delimiter while pars
ing connection value pair.
  at System.Data.SqlClient.ConStringUtil.ParseStringIntoHashtable(String conStr
 ing, Hashtable values)
  at System.Data.SqlClient.ConStringUtil.ParseConnectionString(String connectio
 nString)
  at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
  at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
  at DestructorsExample.Class2.Finalize()
Destructor of Class1


 

原创粉丝点击