The previous post on Code Contracts was about Contract.Requires. That method comes with an overload, which is a generic one that takes an Exception type as the generic type parameter. The purpose of this method is mainly in line with that of the Contract.Requires method that I explained in the previous post here.
The original code sample contained a few ArgumentExceptions that were thrown if certain conditions were not met. The use of the Contract.Requires method made the code more succinct with less clutter, but the exceptions were nowhere to be found. In case the precondition is not met in the code that uses Contract.Requires, a ContractException will be thrown at runtime. Sometimes it is feasible though to throw a more specific exception, like the ArgumentExceptions that were thrown in the IF-THEN-THROW constructions.
Just to step back to the code we had initially:
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);
}
This code is very specific about the exceptions. About the ArgumentOutOfRangeException one could argue that it is actually not a correct exception to throw here, since there is no specific range, but beyond that, the exceptions serve a purpose. It is up to the requirements of the final code and build whether or not the exception must be of the ArgumentException family, or it should be a more ‘general’ ContractException, since it involves the predefined contract. When it is necessary to have the existing exceptions, one should use the Contract.Requires<TException> overload. The example code would end up looking like this:
public string RepeatFirstCharacter(string input, int count)
{
Contract.Requires<ArgumentNullException>(input != null);
Contract.Requires<ArgumentException>(input.Length >= 0, "The input should have at least one character.");
Contract.Requires<ArgumentOutOfRangeException>(count > 0);
return new string(input.ToCharArray(0, 1)[0], count);
}
Beyond the fact that the more specific exception is used on contract failure, all other points mentioned in the post on Contract.Requires, also apply to Contract.Requires<TException>. The overload has an additional caveat though. The exception type that is to be thrown must have a public constructor accepting a single string argument. If such a constructor can not be determined at runtime, an internal ContractException will be created and thrown instead.
To conclude the posts on preconditions, the next will handle about Contract.EndContractBlock(). Even though it is not specific for preconditions, it will only truly serve a purpose when it appears at the end of legacy preconditions that are stated in the form of IF-THEN-THROW.
That’s it for now.
Meile