0

Trying to understand how an object is reclaimed. Read here that the order of objects being reclaimed is not guaranteed.

For example, my class has the following code -

class MyClass: IDisposable
{
    private List<string> _fileNames;
    
    // some other code and methods here with constructor
    
    ~MyClass()
    {
        Dispose(false);
    }

    private void Dispose(bool dispose)
    {
        foreach (string file in _fileNames)
        {
             // log something with dispose 
             File.Delete(file);
        }
    }
}

Does it mean that when the GC tries to reclaim this object, there is no guarantee that the _fileNames is still populated with strings and not null? Or, can one still use the list of strings above to free up resources? In the link posted, it mentions -

'The finalizers of two objects are not guaranteed to run in any specific order, even if one object refers to the other. That is, if Object A has a reference to Object B and both have finalizers, Object B might have already been finalized when the finalizer of Object A starts.'

So does it mean that the list may no longer be useful in the Dispose (assuming dispose is false)?

IceMan
  • 123
  • 2
  • 11
  • Does this answer your question? [Destructor execution order?](https://stackoverflow.com/questions/30368849/destructor-execution-order) – Charlieface Oct 23 '22 at 10:25
  • 1
    Why should `_fileNames` be or contain `null`? There is only one finalizer in your posted code, so there can’t be any ordering problem. – Holger Oct 24 '22 at 12:48

1 Answers1

1

If the method call comes from a finalizer, only the code that frees unmanaged resources should execute. The implementer is responsible for ensuring that the false path doesn't interact with managed objects that may have been disposed. This is important because the order in which the garbage collector disposes managed objects during finalization is non-deterministic.

Implementing Dispose

But it's moot because you shouldn't implement finalizers. Pretty much ever.

Consider your example. If someone fails to call Dispose, your object will eventually become unreachable, and eventually GC will figure that out and try to run your finalizer. However it's not guaranteed to ever run, and it's not guaranteed to run in any particular timeframe. It could be hours.

So what is really gained by adding the finalizer? Not much.

Failing to call Dispose on an IDisposable is a bug. So the only time the finalizer will run is when there's a bug. So it might be a good idea to have a finalizer that just throws an exception, crashing your program, so you can find and fix the whatever didn't call Dispose(). But having a finalizer try to clean up after buggy code is usually a bad idea.

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67