Home > Mobile >  Destructor vs IDisposable - which one get called more reliably by C# garbage collector?
Destructor vs IDisposable - which one get called more reliably by C# garbage collector?

Time:01-17

Can't seem to find consistent answers on the Internet. It looks like CLR GC makes a "decision" on whether to call destructors during garbage collection. This would imply that sometimes destructors won't be called. The way our legacy code base is structured, "using" blocks can't always be used, and the object instances do have certain resources that need to be released after object is no longer needed. I need a guaranteed way for GC to call a destructor. Would implementing IDisposable guarantee .Dispose being called on garbage collection? What is the best practice here?

I tried using ~ClassName(){ } and destructor doesn't always get called.

CodePudding user response:

Destructor

The preferable term is finalizer AFAIK.

It looks like CLR GC makes a "decision" on whether to call destructors during garbage collection

AFAIK GC does not call finalizers during collection, they are called after GC marks objects ready for finalization (this also results in extending object lifespan which can have performance implications) and places them into finalization queue. In "normal" program flow finalizers should eventually be run but there are some corner cases which can prevent that.

I need a guaranteed way for GC to call a destructor.

There is no such way. Finalizers are non-deterministic and should be used as "last resort" measure.

Would implementing IDisposable guarantee .Dispose being called on garbage collection?

No, IDisposable has nothing to do with GC, IDisposable will be called only "manually" (i.e. either directly or via using), that's it.

What is the best practice here?

Implement IDisposable and invoke it (manually or via using).

Useful resources:

CodePudding user response:

The finalizer (destructor) is unreliable.

Ideally you should implement the IDisposable interface and use using blocks whenever possible. This article from microsoft has info about this

For your case a combination of IDisposable and finalizers may be the best case. There is a pattern from microsoft that you can also generate automatically in Visual Studio.

From microsoft:

using System;

class BaseClassWithFinalizer : IDisposable
{
    // To detect redundant calls
    private bool _disposedValue;

    ~BaseClassWithFinalizer() => Dispose(false);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            if (disposing)
            {
                // TODO: dispose managed state (managed objects)
            }

            // TODO: free unmanaged resources (unmanaged objects) and override finalizer
            // TODO: set large fields to null
            _disposedValue = true;
        }
    }
}
  • Related