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?
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.
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.
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.
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.
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];
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];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With