Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does CodeContracts warn me that "requires unproven: index < @this.Count" even though I have already checked the count?

I have code that looks something like this:

public class Foo<T> : ObservableCollection<T>
{
    private T bar;

    public Foo(IEnumerable<T> items)
        : base(items.ToList())
    {
        Contract.Requires(items != null);

        if (this.Any())
            this.bar = this[0]; // gives 'requires unproven: index < @this.Count'
    }
}

Shouldn't the Any check account for index 0? Am I doing something wrong, or does CodeContracts just not recognize this case?

like image 958
Matthew Avatar asked Jul 28 '11 18:07

Matthew


People also ask

What are the benefits of using code contracts?

Improved testing: Code contracts provide static contract verification, runtime checking, and documentation generation. Automatic testing tools: You can use code contracts to generate more meaningful unit tests by filtering out meaningless test arguments that do not satisfy preconditions.

What are preconditions in a code contract?

Code contracts provide a way to specify preconditions, postconditions, and object invariants in .NET Framework code. Preconditions are requirements that must be met when entering a method or property. Postconditions describe expectations at the time the method or property code exits.

Where can I find the classes for code contracts?

The classes for code contracts can be found in the System.Diagnostics.Contracts namespace. The benefits of code contracts include the following: Improved testing: Code contracts provide static contract verification, runtime checking, and documentation generation.

How do you identify an invariant method in a contract?

The invariant methods are identified by being marked with the ContractInvariantMethodAttribute attribute. The invariant methods must contain no code except for a sequence of calls to the Invariant method, each of which specifies an individual invariant, as shown in the following example.


2 Answers

LINQ's .Any and the item accessor [0] are unrelated enough that Code Contracts hasn't been made to consider them to be the same thing. Since this.bar would be initialized using a default value anyway, it's probably best to just do this:

Contract.Requires(items != null);
this.bar = items.FirstOrDefault();

This would not only resolve the possibility of thread-safety which AakashM points out, but it is also slightly more performant. Since you know this is a collection (and therefore has a .Count), another option would be:

if(this.Count > 0)
    this.bar = this[0]; 
like image 106
StriplingWarrior Avatar answered Oct 17 '22 07:10

StriplingWarrior


None of the LINQ methods are annotated with the Contracts API. Hence when the verifier runs on this method it acquires no new data about the value of Count. This is why you see the warning.

One way to work around this is to use Assume to tell the verifier the count is valid at this point.

if (this.Any()) {
  Contract.Assume(this.Count > 0);
  this.bar = this[0];
}
like image 36
JaredPar Avatar answered Oct 17 '22 05:10

JaredPar