Finalizers
Finalizers are used to cleanup the class resources. It’s similar to the C++ destructors except the fact that it’s called by garbage collector and the we can’t make sure when the finalizer will be called. Note that the finalizers are not used to release the memory or managing memory. Rather It’s used to free up the resources like releasing the database connections, releasing the file handles, deleting the temporary files created etc. or an explicit activity which the garbage collector is not aware of.
The declaration is identical to C++ destructors. Since it’s being called by Garbage collection there’s no requirement to mention the access specifier.
Garbage collector call the finalizer from a separate thread. If the finalizer throws some exceptions, it will be difficult to debug as it’s outside the debugger’s context. Use defensive programming mechanisms like checking against null before accessing the object to avoid the exceptions.
Deterministic Finalization with using statement
The finalizers are used to free up the memory and the programmer can’t assure when the it will be called during compile time as it’s completely depends upon the garbage collector’s memory management logic. It’s possible to provide explicit cleanup functions for the developers to freeup the resources even before the garbage collector execute the finalizer. But the developer has to call the function explicitly, C# Base class library has implemented an interface class called IDispose, which allow us to implement the ‘Dispose’ interface.The object can be constructed with using statement for deterministic finalization. See the code for implementation details.
Note that IDisposable contains one additional important call. An object can have both finalizer and Dispose Interface implementation. Once if the Dispose function do the cleanup activity, it’s not really required to call finalizer call again. So we can call System.GC.SuppressFinalize(this); to suppress the finalizer call. It’s a good practice to code the object as unsusable after Dispose operation.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace FinalizerSample
{
class Program
{
static void Main(string[] args)
{
// Working with Dispose Interface. (Deterministic finalizer)
using (MyFileInfo fileInfo = new MyFileInfo(Path.GetTempPath()))
{
Console.WriteLine(fileInfo.Info.Directory.ToString());
Console.WriteLine(fileInfo.Info.CreationTime.ToString());
} // Dispose interface will be called here
// not really sure when the finalizer will be called
MyFileInfo ff = new MyFileInfo(Path.GetTempPath());
Console.WriteLine(ff.Info.Directory.ToString());
Console.WriteLine(ff.Info.CreationTime.ToString());
Console.WriteLine("-----Exiting App-----");
// the normal finalizer for the objects will be called here usually
}
}
public class MyFileInfo : IDisposable
{
public MyFileInfo( string filename)
{
Info = new FileInfo(filename);
}
public FileInfo Info
{
get;
private set;
}
// Finalizer
~MyFileInfo()
{
Console.WriteLine("Finalizer");
}
#region IDispose overrides
public void Dispose()
{
Console.WriteLine("-->Calling Dispose\n");
// Already the resources are freed up. Avoi calling Finalizer
System.GC.SuppressFinalize(this);
}
#endregion
}
}