Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using invariant for IDisposable

Consider the following IDisposable class:

class MyClass : IDisposable
{
    public bool IsDisposed { get; private set; } = false;

    public void Dispose()
    {
        IsDisposed = true;
    }
}

Every method in this class, including Dispose(), should begin with a check like this:

if (IsDisposed)
{
    throw new ObjectDisposedException(...);
}

Since it is tedious and repetitive to write this in all methods, I would like to use contract invariant:

public class MyClass : IDisposable
{
    ...

    [ContractInvariantMethod]
    private void objectInvariant()
    {
        Contract.Invariant(!IsDisposed)
    }

    ...
}

However, this only ensures IsDisposed is false at the end of each public method, excluding Dispose().

Once Dispose() is called, the check should be done at the beginning of each method (including Dispose()). Otherwise the obejct will be in invalid state during the method run, potentially leading to difficult bugs.

Hence contract invariants are not really usable for IDisposable. Or am I missing something?

Is it possible to force invaraiants to be also used as preconditions or do I really have to write the same precondition (!IsDisposed) to all methods manually?

like image 720
Libor Avatar asked Oct 12 '15 16:10

Libor


1 Answers

You seem to be misunderstanding invariants. From the documentation:

Object invariants are conditions that should be true for each instance of a class whenever that object is visible to a client.

(Emphasis mine) Your object can very well be visible to a client after you called Dispose, making the object "invalid". But it actually is a valid state for your object to have IsDisposed == true.

You are really looking for Pre-Conditions.

like image 53
Daniel Hilgarth Avatar answered Sep 25 '22 16:09

Daniel Hilgarth