Alpha
Alpha

Reputation: 7868

Why is Dispose being called, if my object was never constructed?

Based on this post, I created a bridge between components for Windows forms and IDisposable objects. It pretty much looks like this:

namespace MyApp
{
    public class Disposer: Component
    {
        private readonly Action<bool> _dispose;

        public Disposer(Action<bool> disposeCallback)
        {
            if (disposeCallback == null)
                throw new ArgumentNullException(nameof(disposeCallback));

            this._dispose = disposeCallback;
        }

        protected override void Dispose(bool disposing)
        {
            this._dispose(disposing);
            base.Dispose(disposing);
        }
    }
}

So far so good. Then I created unit tests, including one for the particular validation on the constructor argument.

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Disposer_ShouldNotAllowNullActions()
{
    new Disposer(null);
}

Here's the catch: not only my test fails, but it actually gets aborted. The test platform itself crashes (ReSharper test runner). By digging into my Windows Event Viewer I could see that the Dispose() method is being called, and since this._dispose is essentially null at this point, it fails with a NullReferenceException.

I fixed this with providing an empty lambda as the default value.

But if the constructor throws an exception (which I confirmed it does), why is the Dispose method called at all?

Upvotes: 2

Views: 290

Answers (2)

D Stanley
D Stanley

Reputation: 152624

why is the Dispose method called at all?

The finalizer for a class is called even if the constructor throws an exception. The finalizer for Component calls Dispose():

    ~Component() {
        Dispose(false);
    }

Since you override Dispose(bool), your override is called if the constructor throws an exception. Since this is a real possibility in your code, I'd suggest making sure both this and this._dispose are not null.

Upvotes: 1

C.Evenhuis
C.Evenhuis

Reputation: 26446

The Component class must have a finalizer that calls this.Dispose(), which causes your override to be called.

Finalizers are run even if the constructor did not complete - this allows all resources that were allocated before the constructor failed to be cleaned up.

Upvotes: 6

Related Questions