Search This Blog

Sunday, July 31, 2011

Destructor, Finalize and IDisposable Interface


Destructors
Destructors are used to destruct instances of classes.
Remarks
·         A class can only have one destructor.
·         Destructors cannot be inherited or overloaded.
·         Destructors cannot be called. They are invoked automatically.
·         A destructor does not take modifiers or have parameters.
For example, the following is a declaration of a destructor for the class Car:

class Car { ~ Car() // destructor { // cleanup statements... } }
The destructor implicitly calls Finalize on the object's base class. Therefore, the preceding destructor code is implicitly translated to:
protected override void Finalize() { try { // cleanup statements... } finally { base.Finalize(); } }
This means the Finalize method is called recursively for all of the instances in the inheritance chain, from the most-derived to the least-derived.
Note
Empty destructors should not be used. When a class contains a destructor, an entry is created in the Finalize queue. When the destructor is called, the garbage collector is invoked to process the queue. If the destructor is empty, this simply results in a needless loss of performance.
The programmer has no control over when the destructor is called because this is determined by the garbage collector. The garbage collector checks for objects that are no longer being used by the application. If it considers an object eligible for destruction, it calls the destructor (if any) and reclaims the memory used to store the object. Destructors are also called when the program exits.
It is possible to force garbage collection by calling Collect but in most cases, this should be avoided because it may result in performance issues.
Using Destructor to release resources
Explicit Release of Resources

If your application is using an expensive external resource, it is also recommended that you provide a way to explicitly release the resource before the garbage collector frees the object. You do this by implementing a Dispose method from the IDisposable interface that performs the necessary cleanup for the object. This can considerably improve the performance of the application. Even with this explicit control over resources, the destructor becomes a safeguard to clean up resources if the call to the Dispose method failed.
Example
The following example creates three classes that make a chain of inheritance. The class First is the base class, Second is derived from First, and Third is derived from Second. All three have destructors. In Main(), an instance of the most-derived class is created. When the program runs, notice that the destructors for the three classes are called automatically, and in order, from the most-derived to the least-derived.

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
Second's destructor is called
First's destructor is called
Object.Finalize Method 
Allows an object to attempt to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection.
Remarks
Finalize is protected and, therefore, is accessible only through this class or a derived class.
This method is automatically called after an object becomes inaccessible, unless the object has been exempted from finalization by a call to SuppressFinalize. During shutdown of an application domain, Finalize is automatically called on objects that are not exempt from finalization, even those that are still accessible. Finalize is automatically called only once on a given instance, unless the object is re-registered using a mechanism such as ReRegisterForFinalize and GC.SuppressFinalize has not been subsequently called.
Every implementation of Finalize in a derived type must call its base type's implementation of Finalize. This is the only case in which application code is allowed to call Finalize.
Finalize operations have the following limitations:
·         The exact time when the finalizer executes during garbage collection is undefined. Resources are not guaranteed to be released at any specific time, unless calling a Close method or a Dispose method.
·         The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already finalized when the finalizer of Object A starts.
·         The thread on which the finalizer is run is unspecified.
The Finalize method might not run to completion or might not run at all in the following exceptional circumstances:
·         Another finalizer blocks indefinitely (goes into an infinite loop, tries to obtain a lock it can never obtain and so on). Because the runtime attempts to run finalizers to completion, other finalizers might not be called if a finalizer blocks indefinitely.
·         The process terminates without giving the runtime a chance to clean up. In this case, the runtime's first notification of process termination is a DLL_PROCESS_DETACH notification.
The runtime continues to Finalize objects during shutdown only while the number of finalizable objects continues to decrease.
If Finalize or an override of Finalize throws an exception, and the runtime is not hosted by an application that overrides the default policy, the runtime terminates the process and no active try-finally blocks or finalizers are executed. This behavior ensures process integrity if the finalizer cannot free or destroy resources.
Notes to Implementers: Object.Finalize does nothing by default. It must be overridden by a derived class only if necessary, because reclamation during garbage collection tends to take much longer if a Finalize operation must be run. If an Object holds references to any resources, Finalize must be overridden by a derived class in order to free these resources before the Object is discarded during garbage collection. A type must implement Finalize when it uses unmanaged resources such as file handles or database connections that must be released when the managed object that uses them is reclaimed. See the IDisposable interface for a complementary and more controllable means of disposing resources. Finalize can take any action, including resurrecting an object (that is, making the object accessible again) after it has been cleaned up during garbage collection. However, the object can only be resurrected once; Finalize cannot be called on resurrected objects during garbage collection.
Destructors are the C# mechanism for performing cleanup operations. Destructors provide appropriate safeguards, such as automatically calling the base type's destructor. In C# code, Object.Finalize cannot be called or overridden.
IDisposable Interface 
Defines a method to release allocated unmanaged resources.
[ComVisibleAttribute(true)] public interface IDisposable

Remarks
The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used, however, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.
Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed.

Calling the IDisposable Interface

When calling a class that implements the IDisposable interface, use the try-finally pattern to make sure that unmanaged resources are disposed of even if an exception interrupts your application.
Note that you can use the using statement (Using in Visual Basic) instead of the try-finally pattern.
 Example
C#
using System; using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource. [System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}



No comments :

Post a Comment