Use of System.Diagnostics.Contract in Release builds

1.8k views Asked by At

I previously saw a thread on StackOverflow that had some discussion on this, however I am unable to find it again!

I am interested to know if the System.Diagnostics.Contract classes should be used in 'real code', ie a release build of production code? I ask this, because based on the namespace description it appears the Contract is intended to debugging, or analysis purposes.

It seems like a useful library where pre/post conditions for functionality is important, and may avoid some of the effort in writing lots of if/then/else checks, so if this is the case, is there an alternative in the core libraries?

1

There are 1 answers

0
Joey On BEST ANSWER

Section 5.1 (Argument Validation and Contracts) of the documentation details the three main usage modes you might consider for using Contracts:

  1. Argument validation via Contracts only in Debug builds, not in Release builds.
  2. Validation also in Release builds.
  3. Custom argument validation in Release builds, Contracts only in Debug builds.

So there is at least one usage mode where you'd use Contracts in Release builds, at least as the official documentation is concerned.

Quote:

Before you start using contracts in your own code, you need to make a few decisions that influence what contract forms to use for argument validation and where (see Figure 2). Note that you can make these decisions independently for each managed assembly you produce (each project):

The easiest use of the contract tools is if you decide that you don't need to perform argument validation at runtime in release builds (Usage 1). In that case, you use the contract tools during development, but not on the shipped bits. Remember, you can ship a contract reference assembly along with your release bits so clients can get runtime checking of your parameter validations on their debug builds via call-site requires checking.

The second easiest approach if you need argument validation in your release build is to turn on contract checking in all builds (Usage 2). You therefore take advantage of the tools to produce the runtime strings of your conditions and to perform contract inheritance for you. You can choose to produce specific exceptions for your parameter validations, or have the default ContractException. The risk of using the contract tools in your release build is that you depend on tools that have not reached production quality level.

The trickiest combination is when you want argument validation in release builds, but you are using the contract tool for runtime checking only in debug builds, but not in the release build (Usage 3). In that case, you have to continue writing your argument validation the way you already do, namely using if-then-throw statements (we call them legacy-requires). If you want these to be tool discoverable, add other contracts (such as Ensures) after them, or use Contract.EndContractBlock(), if no other contracts are present. Note that since you are not using the runtime checking tools in the release build, you are not going to get any inheritance of contracts and you have to manually repeat your legacy-requires on overrides and interface implementations. For interface and abstract methods, you still get the most benet if you write contract classes with normal requires and ensures forms so you get checking in your debug builds and they appear in contract reference assemblies and are thus visible to dependent projects and to static checkers.

This also hints at what the alternative using only the other parts of the framework would be: The usual way using if-then-throw.