6

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?

Libor
  • 3,285
  • 1
  • 33
  • 41
  • 4
    "Every method in this class, including Dispose(), should begin with a check like this" - The Dispose method should generally be able to be called multiple times without throwing, so should not contain this check. Also it is common to only do this check in members that cannot be used after the object is disposed - other members don't need the check. – Joe Oct 12 '15 at 17:07
  • Look at this question too. i think it can be helpful. http://stackoverflow.com/questions/9192709/run-a-method-before-all-methods-of-a-class question is about how to call a method before calling anymethod in that class. and probably this answer http://stackoverflow.com/a/9192747/4767498 – M.kazem Akhgary Oct 12 '15 at 17:22

1 Answers1

4

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.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • I see. I am basically looking for a way to avoid putting same precondition to basically every single method and property. – Libor Oct 12 '15 at 17:10
  • 1
    That would be a task for an AOP library like PostSharp. You also could create a dynamic interceptor using LinFu. – Daniel Hilgarth Oct 12 '15 at 17:11