Home > Back-end >  Properly dispose derived class
Properly dispose derived class

Time:10-26

I am trying to implement the IDisposable pattern on a derived class, and it's not working as expecting to work,

Suppose I have two classes and I want to call the Dispose method of the derived class:

Below is the code of my base class

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

    // 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;
        }
    }
}

And I've something like this as a derived class

public class DerivedClass : BaseClass
{
    // To detect redundant calls
    private bool _disposedValue;

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            if (disposing)
            {
                
            }

            _disposedValue = true;
        }

        // Call base class implementation.
        base.Dispose(disposing);
    }
}

And I've some wrapper class

public class WrapperClass : IDisposable
{
    public ReadOnlyCollection<BaseClass> Items { get; set;}

    // To detect redundant calls
    private bool _disposedValue;

    // 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)
            {
                    foreach (var item in Items)
                    {
                        item.Dispose();
                    }
            }

            _disposedValue = true;
        }
    }
}

My issue is in the wrapper class, it doesn't call the Dispose method of the DerivedClass, and it calls the Dispose method of the BaseClass instead.

Update

It's my bad, I forget to say that the collections of items were created by NSubstitute like below:


// Having this will not call the Dispose method of the derived class
Items = new ReadOnlyCollection<BaseClass>(new List<BaseClass>
{
    Substitute.For<DerivedClass>()
})

// Having this will call the Dispose method of the derived class
Items = new ReadOnlyCollection<BaseClass>(new List<BaseClass>
{
    new DerivedClass>()
})

CodePudding user response:

The public implementation of the Dispose() pattern in the documentation is there as an example to handle every case and contingency. It's always "safe" to do the whole thing, but it's also true that most of the time you can skip most of the pattern.

Especially regarding finalizers: you should only need a finalizer if you are creating an original wrapper implementation for a brand new kind of unmanaged resource. Each unmanaged resource type only needs one finalizer, at the root of the IDisposable inheritance tree. And if you don't add a finalizer, you don't need to worry about GC.SuppressFinalize(). Remove that, and some other balls drop as well.

In short, we can reduce the pattern for your DerivedClass all the way down to this:

public class DerivedClass : BaseClass
{

}

This DerivedClass type still provides the Dispose() method and IDisposable implementation inherited from it's parent, and if it doesn't introduce any other unmanaged resources that's all it needs.

CodePudding user response:

My issue is in the wrapper class, it doesn't call the Dispose method of the DerivedClass, and it calls the Dispose method of the BaseClass instead.

When the base.Dispose() calls Dispose(true) the method override in the derived class is executed, which in turn will call base. Dispose(true).

CodePudding user response:

DerivedClass doesn't appear to override Dispose(). Consequently, the base class version is invoked.

Add a public void Dispose() method that calls your protected void Dispose(bool disposing) implementation in DerivedClass.

  • Related