When not using ccrewrite (say the project is built by another developer without CC installed),
Is Contract.Requires<T>(cond)
silently stripped or does it still result in behavior equivalent to if (!cond) { throw new T() }
? (I don't care if it's another method call or two - but it should "always be checked".)
I ask because Contract.Requires<T>
appears to behave differently than Contract.Requires
, but I'm not sure "how" or "when".
The goal is to replace the construct on public contracts
if (x != null) throw new ArgumentNullException();
with a CC-compatible version that will still throw an exception when not performing a CC rewrite during the build step.
While the above with EndContractBlock
does work with "Custom Parameter Validation" (ie. legacy contract mode) I would like to use "Standard Contract Requires" in the project.
I believe there may be an equivalency, because in "Custom Parameter Validation" mode I am not able to use Requires<T>
; if there is no equivalency to an always-required-check, insight as to why would be nice.
I am fine losing Requires
, Ensures
, and leaving in the non-honored invariant contract methods and interface contracts when CC rewriting is not done as I value them for the static analysis - but I need these always-there boundary checks to argue for keeping CC.
Please see the Code Contracts manual. It definitely tells you all you need to know about how the various forms of Code Contract checking works and what options are required to be set when using each form.
Contract.Requires(bool cond)
and Contract.Requires<TException>(bool cond)
?To answer your first question, see section 2.1 Preconditions in the manual. Briefly, here is the difference:
Contract.Requires(bool cond)
This will throw a private Contract.ContractException
exception if the condition evaluates to false
. You cannot catch this exception (since it's private from your point of view)—this is to discourage catching and handling it, thereby making the contracts pretty much worthless.
Contract.Requires<TException>(bool cond)
If the condition evaluates to false
, the specified TException
will be thrown. You cannot use this form without running the contract tools on all builds.
ccrewrite
Specifically, on page 20, in section 5. Usage Guidelines, it tells you all the different forms of contracts that Code Contracts can work with, how they work, and what the build requirements for each are.
I'll briefly summarize, but please, download the manual and read it. It's quite good, though not in any way complete—you have to do a lot of experimentation to learn how to effectively use Code Contracts. Also, if you have access to PluralSight, John Sonmez has a course called Code Contracts which is a great introductory course; and Michael Perry has an awesome course called Provable Code.
If you don't need contract checking in released code, then:
Contract.Requires
everywhereIf you require contract checking on released code, you have two options:
Contract.Requires<TException>
on public API methods (e.g. methods that will be called by users of your library) for which you want to throw specific exceptions, e.g. ArgumentException
.Contract.Requires
For non-public API methods or public API methods for which you don't want to throw a specific exception.if (cond) { throw new Exception(...) }
guard blocks on your public API methodsContracts.EndContractBlock()
after all your if (cond) { throw new Exception(...) }
blocks so that Code Contracts knows these are your contracts.Contract.Requires
for your contracts.One thing to note about the above: Contract checking is always enabled on Debug builds. If other developers on your team will be building this library, they will also need to have Code Contracts installed.
From Section 5.1.3: Forcing Projects to build with Contracts:
If you are using scenario 2 (Requires〈Exn〉) and you make your source code available to other developers, you might want to alert them that they need to use the tools to build your source. If so, you can insert the following snippet into your project file at the end (after the import of CSharp or VisualBasic targets):
<PropertyGroup> <CompileDependsOn>$(CompileDependsOn);CheckForCodeContracts</CompileDependsOn> </PropertyGroup> <Target Name="CheckForCodeContracts" Condition="'$(CodeContractsImported)' != 'true'"> <Error Text="Project requires Code Contracts: http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx" /> </Target>
Also, see Section 6.1: Assembly Mode where it tells you the difference between Custom Parameter Validation and Standard Contract Requires. This section makes it quite clear that the contract rewriter (ccrewrite
) is always run on Debug builds.