Wednesday, October 28, 2009

Visual Studio 2010 and .NET 4.0 Series – Code Contracts

I had written a couple of days ago on my blog about the release of VS2010 and .NET 4 Beta 2. Now that I have had a chance to install and play around a bit, I am hoping to explore some of the new features of .NET 4 and VS 2010 in the next few weeks. I will kick off this week with Code Contracts.

According to MSDN, “Code contracts provide a way to specify preconditions, postconditions, and object invariants in your code”. To work with code contracts .NET 4 now comes with a new namespace System.Diagnostics.Contracts.

As mentioned in the above definition, code contracts can be used to check, pre-conditions, post-conditions and invariants. Pre-conditions are conditions that should be satisfied before a method is invoked; post-conditions are conditions that should be met just before the method finishes execution and invariants validate class state. We will look at Pre-Conditions with an example and a peek into Post Conditions in this post. I will finish this off with another post on Post Conditions example and invariants.

Preconditions

The Contract.Requires method can be used to validate preconditions. An example of this will be to validate parameters that are being passed into a method. To demonstrate this, I will create a new console project and write the code below.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: using System.Diagnostics.Contracts;
   7:  
   8: namespace CodeContractsSample
   9: {
  10:     class Program
  11:     {
  12:         static void Main(string[] args)
  13:         {
  14:             Concatenate(String.Empty, "test");
  15:             Console.ReadLine();
  16:         }
  17:  
  18:         static void Concatenate(string leadingstring, string trailingstring)
  19:         {
  20:             Contract.Requires(leadingstring.Length > 0, "Ensure leading string is valid.");
  21:             Console.WriteLine(String.Concat(leadingstring,trailingstring));
  22:  
  23:         }
  24:     }
  25: }




Let us harp a bit on the Contract.Requires method. The method takes two parameters; the first is a boolean condition that needs to be enforced. The second optional parameter is the message that needs to be displayed if the condition evaluates to false. In the above example, the method makes sure the leading string is not empty.

When I wrote this code and ran it, I found it to my surprise that the contracts were not working. After a bit of research, I found that for contracts to work, you need an additional download. You can find the download at Dev Labs. Once you download and run the installer, you will find an additional tab called Contracts in your solution properties as shown below.

CodeContracts

You can then control how your contracts work in this window. Please note that to without Team System you can do only runtime checking. Running the application now throws the designated message if we pass an empty string to the Concatenate method.

A variant of this is the Requires<> method which takes a generic TException parameter. Below is the code to raise an exception and catch it in code. One thing you have to make sure is you turn off the assert on contract failure setting in the Code Contracts settings tab. This will ensure exceptions are raised from the contracts.



   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5:  
   6: using System.Diagnostics.Contracts;
   7:  
   8: namespace CodeContractsSample
   9: {
  10:     class Program
  11:     {
  12:         static void Main(string[] args)
  13:         {
  14:             try
  15:             {
  16:                 Concatenate(String.Empty, "test");
  17:                 
  18:             }
  19:             //catch the argument null exception raised by the contract
  20:             catch(ArgumentNullException nullString)
  21:             {
  22:                 Console.WriteLine(nullString.Message);
  23:             }
  24:             Console.ReadLine();
  25:         }
  26:  
  27:         static void Concatenate(string leadingstring, string trailingstring)
  28:         {
  29:  
  30:             //raise an exception if the contract fails
  31:             Contract.Requires<ArgumentNullException>(leadingstring.Length > 0);
  32:             Console.WriteLine(String.Concat(leadingstring, trailingstring));
  33:  
  34:         }
  35:     }
  36: }


PostConditions


Though most of the basic concepts are the same for post and preconditions, postconditions offer a bit more flexibility and features that preconditions do not. Postconditions are validated by using the Contract.Ensures method. Postconditions also offer the following capabilities


  • Ability to refer the return value of a method using Contract.Result<T> where T should be of the same type as the return type of the method. Obviously you cannot use Result for methods that do not return anything.

  • Ability to check the value of a variable at the beginning of the method. This can be done by using Contract.OldValue<T>(e) where e is the variable for which you want the old value and T is the type of that variable.

  • Ability to ensure a condition is met when an error is thrown in the method. You can use the Contract.EnsuresonThrow<>.

That is it for this post. I will show you in my next post how to write PostConditions and we will also look at invariants.