Question

Say a factory for SomeDisposable actually is creating/returning a sort of watch dog Wrapper

public class Wrapper : SomeDisposable
{
    public new /*:(*/ Dispose() { ... };
}

and the caller uses like

using (SomeDisposable sd = SomeDisposableFactory.Create(...))
{
} // Wrapper.Dispose() never called.

The Wrapper.Dispose() is never called. If Dispose() were virtual then Wrapper.Dispose() would be called.

The IDisposable interface does not guarantee that the other best practice method virtual Dispose(bool) actually exists or enforce that either be virtual so it cannot be generally relied on to exist (it is only a recommended pattern). Interfaces currently do not allow constraints on virtual.

What are some pros and cons for not making the recommended Dispose() pattern virtual which would have solved this particular dilemma. Should C# allow a way of forcing virtual methods via an interface (since abstract classes aren't popular as contract definitions).

Was it helpful?

Solution

No. The pattern actually says that Dispose() (non-virtual) should call a protected virtual void Dispose(bool) method. This guarantees that the base class Dispose call can pass up the hierarchy properly.

This is spelled out in the documentation for IDisposable:

  • It should provide one public, non-virtual Dispose() method and a protected virtual Dispose(Boolean disposing) method.
  • The Dispose() method must call Dispose(true) and should suppress finalization for performance.
  • The base type should not include any finalizers.

OTHER TIPS

This is already solved.

Disposable types which are not sealed should use the common dispose pattern:

public class DisposableResourceHolder : IDisposable
{
    private SafeHandle resource; // handle to a resource

    public DisposableResourceHolder()
    {
        this.resource = ... // allocates the resource
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // dispose managed resources.
            if (resource != null) resource.Dispose();
        }

        // free unmanaged resources.
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top