This second post in the series on Code Contracts will deal with the Contract.Requires method. In the introduction, I already mentioned that the Contract.Requires method is used to express a precondition. Whenever something has to be validated upfront, the Contract.Requires method is the one to use.
In the old style programming, any precondition would be stated as an IF-THEN-THROW construction, like in the following example:
public string RepeatFirstCharacter(string input, int count)
{
if (input == null)
{
throw new ArgumentNullException("input");
}
if (input.Length < 1)
{
throw new ArgumentException("The input should have at least one character.", "input");
}
if (count <= 0)
{
throw new ArgumentOutOfRangeException("count");
}
return new string(input.ToCharArray(0, 1)[0], count);
}
Not only does this create a lot of clutter, it also expresses the conditions from the negative, exceptional point of view. Looking at the code, it is required for the input to be a non-null string with a length of 1 or more. But the conditional check is on a null string value, and a length smaller than 1. If we were to rewrite the code above with the use of Contract.Requires, we would end up with the following code:
public string RepeatFirstCharacter(string input, int count)
{
Contract.Requires(input != null);
Contract.Requires(input.Length >= 0);
Contract.Requires(count > 0);
return new string(input.ToCharArray(0, 1)[0], count);
}
Now all the clutter has gone. The code is more succinct, and the conditions really reflect the contract in a non-exceptional manner. Given the fact that in many software development cycles the specifications are mainly written in terms of requirements, it’s a good thing to have this also in the code. Since the Code Contract preconditions, post conditions, object invariants etc. can all be merged into the generated XML documentation, this also means the requirements will also appear in them as well.
Moreover, the contracts as defined using the IF-THEN-THROW style will only affect the current call. If the RepeatFirstCharacter method had been defined as a virtual method, any derived class that implements an override will have to check for the contract itself. When using Code Contracts, this is no longer necessary. The binary rewriter used by Code Contracts will make sure the contract is also exposed in the derived method as well as in the base method.
All this comes with a few caveats though. Besides the fact that Contract.Requires calls must be at the beginning of the method (which is quite logical given their nature), the contract must only reference members with at least the same visibility as the enclosing method. Since the contract is exposed to clients calling the method, this requirement makes a lot of sense. Another caveat is that on a derived method additional requirements can not be set. This is one that also makes a lot of sense, since the interface definition largely determines the contract. And on an override, the interface isn’t changed, so why should the contract?
This method should be used for those preconditions that do not enforce a particular exception to be thrown, e.g. for backward compatibility reasons. In case a particular exception should be thrown one would have to use Contract.Requires<TException>(Boolean) method instead. I will dig into that method in the next post in this series.
That’s it for now.
Meile