How to use Finalize with managed resources?
Asked Answered
P

1

1

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"

Primeval answered 15/4, 2012 at 17:27 Comment(5)
You are trying to do the job that the garbage collector does. As long as there are live references to B objects, A cannot be collected. Once all B's are collected, A gets collected too. Now it doesn't matter anymore in which order they are finalized.Boyer
@HansPassant: does this include the IsFinalizingForUnload + HasShutdownStarted scenarios?Primeval
Nothing special about those conditions, just a finalizer sweep when your program shuts down. It is pretty unclear to me why you are fretting about any of this.Boyer
@HansPassant: it all began after discovering code where Dispose (through using) was closing something that it shouldn't have been. That lead to trying to get a better handle on dispose + unmanaged in general... and... as a result have discovered some edge cases + .net framework conventions.Primeval
@HansPassant: learning freachable + resurrection gives confidence. btw: in this situation, not implementing finally on children objects (as the framework does) is the best way forward. btw: AddMemoryPressure, RemoveMemoryPressure, and ReRegisterForFinalize look to be quite useful for some all be it rare situations. I wouldn't know about them otherwise.Primeval
G
2

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.

Gudrunguelderrose answered 15/4, 2012 at 17:32 Comment(2)
in [2] Mr Richter on pp. 537 says, "While finalization is almost exclusively used to release a native resource, it can occasionally be useful with managed resources too." Sounds to me like there's a way. I haven't 100% groked this chapter yet though... hence my appeal to the experts.Primeval
He is referring to the possibility to use finalization for object pools I guess. You can't control order, though, except for what I mentioned.Gudrunguelderrose

© 2022 - 2024 — McMap. All rights reserved.