This is the approach one should follow to clean up internal unmanaged resources. Remember one thing you should use this only if make use of some unmanaged stuff that you want to be cleaned up before your application closes in a better way so that there are no leaks. If you are just using all managed stuff then you should not need to write Finalize() methods only Dispose() pattern would work. Else GC is very intelligent itself to handle all the stuff & auto optimize itself. Rest being said lets focus on practical example that what should we follow in order to write robust code.
Let us say we have some class that does a bit of work with unmanaged types. We follow both the finalize & dispose patterns so that if the user forgot’s to call Dispose(), then the garbage collector cleans up the stuff by calling finalize(), & as long as user dispose off objects, the garbage collector doesn’t need to finalize things. So in this model, we have best technique & doesn’t end up with leaking things. But remember if we are disposing things ourselves then we can afford to call other managed types around & dispose them too if required but if Garbage Collector does Finalize() the object then we can’t reference or call any other managed objects around, since we can’t be sure if they exist or not.
You should also be aware that objects having Finalize() method are cleaned by GC in two collections. When an object is allocated on managed heap, the runtime determines if it supports Finalize() method & if it does then it is marked as finalizable, & a pointer to it is stored on finalization queue. This queue helps, so that the objects must be finalized before they are removed from heap. When GC starts executing to free memory, then it checks each entry in finalization queue & copies the object off the heap to another managed structure named as freachable (finalization reachable). A separate thread is used by GC to invoke Finalize() on each object present on the freachable table at the next Garbage Collection.
You can also check out some new GC class methods available in .NET 3.5 i.e. AddingMemoryPressure() & RemovingMemoryPressure() methods.