1

Basically, I have a virtual method to propagate certain mandatory postconditions to subclasses. Here's a simplified version and the strange warnings the static checker generates (edit - my example was incomplete. It's right now):

public abstract class InitializerClass
{
    protected bool _initialized

    public bool IsInitialized
    {
        get { return _initialized; }
    }

    public virtual void Initialize()
    {
        //Warning CodeContracts: Missing precondition in an externally visible
        //method. Consider adding Contract.Requires(this.IsInitialized); for
        //parameter validation
        Contract.Ensures(IsInitialized);
    }
}

this is the other class:

public abstract class OrderingClass
{
    protected bool _ordered

    public bool IsOrdered
    {
        get { return _ordered; }
    }

    public override void Initialize()
    {
        //Message CodeContracts: Suggested assume: Contract.Assume(this.IsOrdered);
        Contract.Ensures(IsOrdered);
    }
}

in fact, both warnings are pointing to the closing curly brace of the methods, in the lines just bellow the Contract.Ensure calls. What's wrong with my code?

user2212990
  • 177
  • 1
  • 9
  • I clearly can't add `Contract.Requires(IsInitialized)` to `InitializerClass.Initialize`, because ensuring `IsInitialized` is set to true as a post-condition is the point of the contract. Those things are mutually exclusive. Same thing with the `OrderingClass.Initialize` override. Am I missing something or is the static checker just really confused? – user2212990 Jul 02 '13 at 09:29
  • There actually is code setting _initialized to true in the method, right? Better add it to be clear. – H H Jul 03 '13 at 09:46
  • No such warning is produced using CodeContracts version 1.7.11202.10 static checking, with the warning level and options cranked up, whichever way I try to fix the code (in addition to Henk's comment: missing semicolumns, override without base class). – Stein May 27 '15 at 19:39

1 Answers1

0

You are getting this error because Code Contracts cannot verify that calling Initialize() will result in IsInitialized returning true. This is because there is no code in the body of Initialize() that sets the value of IsInitialized to true, hence the analyzer is warning you that the code is assuming IsInitialized is true on entry to Initialize(), and that you should make this precondition explicit.

There are two ways to eliminate the warning.

First, add the suggested pre-condition:

public virtual void Initialize()
{
    Contract.Requires(IsInitialized);
    Contract.Ensures(IsInitialized);
}

Second, set the value of IsInitialized to true:

public virtual void Initialize()
{
    IsInitialized = true;
    Contract.Ensures(IsInitialized);
}

You will need to add a private setter to IsInitialized in order for the above code to work.

public bool IsInitialized
{
    get { return _initialized; }
    private set { __initialized = value; }
}

Simply setting _initialized = true in Initialize() probably won't allow Code Contracts to verify the post-condition, hence adding the private setter. However, having said that adding the following contract to IsInitialized may negate the need to add the property setter:

public bool IsInitialized
{
    get
    {
        Contract.Ensures(Contract.Result<bool>() ^ !_initialized);
        return _initialized; 
    }
}

You are getting the warning inOrderingClass for the exact same reason. Code Contracts suggests Contract.Assume() because you cannot use Contract.Requires() in overrides.

Ɖiamond ǤeezeƦ
  • 3,223
  • 3
  • 28
  • 40