Is there a way to detect whether or not an object has called GC.SuppressFinalize?
I have an object that looks something like this (full-blown Dispose pattern elided for clarity):
public class ResourceWrapper {
private readonly bool _ownsResource;
private readonly UnmanagedResource _resource;
public ResourceWrapper(UnmanagedResource resource, bool ownsResource) {
_resource = resource;
_ownsResource = ownsResource;
if (!ownsResource)
GC.SuppressFinalize(this);
}
~ResourceWrapper() {
if (_ownsResource)
// clean up the unmanaged resource
}
}
If the ownsResource
constructor parameter is false
, then the finalizer will have nothing to do -- so it seems reasonable (if a bit quirky) to call GC.SuppressFinalize
right from the constructor. However, because this behavior is quirky, I'm very tempted to note it in an XML doc comment... and if I'm tempted to comment it, then I ought to write a unit test for it.
But while System.GC has methods to set an object's finalizability (SuppressFinalize, ReRegisterForFinalize), I don't see any methods to get an object's finalizability. Is there any way to query whether GC.SuppressFinalize has been called on a given instance, short of buying Typemock or writing my own CLR host?
If you want to confirm that finalization has been suppressed if your object doesn't own the resource, perhaps you could have the finalizer assert that it owns the resource? The test would have to do GC.Collect and GC.WaitForPendingFinalizers, but production code wouldn't have anything extra except the assert (which could be omitted from the production build). One slight caveat with the assert: if the thread that creates the object dies between creating the object and setting the ownership status, the finalizer may run inappropriately.
That having been said, I wonder whether it would be better to have an abstract ResourceWrapper type, with separate subtypes OwnedResourceWrapper and SharedResourceWrapper, that own or do not own the resource in question. Then the subtype that doesn't own resources wouldn't need to have a finalizer in the first place. Note that it may be useful for SharedResourceWrapper to implement IDisposable as a no-op.