As mentioned earlier, it is illegal to call a finalizable object in a finalizer, because it is possible that the finalizable object has been finalized already. You must not make assumptions about the order in which objects are finalized—with one exception.
In the namespace System::Runtime::ConstrainedExecution, there is a special base class called CriticalFinalizerObject. Finalizers of classes that are derived from CriticalFinalizerObject are guaranteed to be called after all finalizers of classes that are not derived from that base class. This leaves room for a small refinement of the finalization restriction. In non-critical finalizers it is still illegal to call other objects with non-critical finalizers, but it is legal to call instances of types that derive from CriticalFinalizerObject.
The class System::IO::FileStream uses this refinement. To wrap the native file handle, FileStream uses a handle wrapper class that is derived from CriticalFinalizerObject. In the critical finalizer of this handle wrapper class, the file handle is closed. In FileStream's non-critical finalizer, cached data is flushed to the wrapped file. To flush the cached data, the file handle is needed. To pass the file handle, the finalizer of FileStream uses the handle wrapper class. Since the handle wrapper class has a critical finalizer, the FileStream finalizer is allowed to use the handle wrapper class, and the file handle will be closed after FileStream's non-critical finalizer has flushed the cached data.
Was this article helpful?