Finalizers are needed to guarantee that limited resources exit back to the system, such as file descriptors, sockets, kernel objects, etc. Since the finalizer always works at the end of the life of objects, this is the designated place to release these pens.
The Dispose pattern is used to provide deterministic destruction of resources. Since the garbage collector in .net time mode is not deterministic (which means you can never be sure when the runtime will collect old objects and call their finalizer), a method is needed to ensure a deterministic release of system resources. Therefore, when you correctly implement the Dispose template, you provide a deterministic release of resources, and in cases where the consumer is careless and does not dispose of the object, the finalizer will clear the object.
A simple example of why Dispose is required can be a quick and dirty logging method:
public void Log(string line) { var sw = new StreamWriter(File.Open( "LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)); sw.WriteLine(line);
In the above example, the file will remain locked until the garbage collector calls the finalizer on the StreamWriter object. This creates a problem because, in the meantime, the method may be called again to write the log, but this time it will fail because the file is still locked.
The correct way is to destroy an object when it is executed with it:
public void Log(string line) { using (var sw = new StreamWriter(File.Open( "LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) { sw.WriteLine(line); }
BTW, technically finalizers and destructors mean the same thing; I prefer to call finalizers of C # destructors, because otherwise they tend to mix people with C ++ destructors, which, unlike C #, are deterministic.