How to use Finalize with managed resources?

2019-07-26 05:42发布

I'm not 100% clear on how an instance of class A can be defined to exist until after the last instance of class B is finalized.

Or in other words, I'd like all B's to call close&dispose methods in A inside the B finalisation... and for that to happen before A itself is finalized.

The scenario:

A. I've got a managed wrapper for an unmanaged resource. For an analogy, lets call A a file system

B. managed resources that refer to A, that in turn have requested an unmanaged resource via the A wrapper. For an analyogy, lets call B a file.

Additional request --> I'd like the using syntax to play nicely. i.e. calling the using dispose explicitly should not dispose the unmanaged resource. The object will live in an object pool. It should only be disposed when it leaves the object pool.

class SomeClass() : IDisposable{

    public SomeClass(){}

    public ~SomeClass(){
       // dispose of unmanaged here?
    }

    // Dispose(bool disposing) executes in two distinct scenarios.
    // If disposing equals true, the method has been called directly
    // or indirectly by a user's code. Managed and unmanaged resources
    // can be disposed.
    // If disposing equals false, the method has been called by the
    // runtime from inside the finalizer and you should not reference
    // other objects. Only unmanaged resources can be disposed.
    public void Dispose(bool disposing) {
        if (disposing) {
            // dispose managed
        } else {
            // dispose unmanaged?
        }
    }

    public void Dispose() {
        Dispose(true);
        //GC.SuppressFinalize(this);
    }

}

References:

[1] Why Finalize method not allowed to override

[2] CLR via C Sharp 3rd Ed. Ch. 21. CriticalFinalizerObject. Particularly pp. 537 "Using Finalization with Managed Resources"

1条回答
一夜七次
2楼-- · 2019-07-26 06:05

You cannot control finalization order in general. You can control a two-phase order, though, using CriticalFinalizerObject. Also look at the SafeHandle infrastructure and how FileStream does it.

If that is not enough, you can control lifetimes arbitrarily by creating object references from a static class member (e.g. a List or Dictionary). Only when you release those references finalization can occur. So you'd create a reference to A which you clear once you notice that a GCHandle to B has become invalid.

查看更多
登录 后发表回答