Introduction
.NET 4.0 is just around the corner and many new features are making their presence felt. One such feature is related to the quality of .NET code. This functionality just looks like a cool wrapper for Debug.Assert
. But exploring details helped me understanding its power. [And hence, I guess, I am writing this article.]
If you prefer to watch this demo on video – then check out this channel 9 clip. Code contract bits can be downloaded from here and it works with VS 2008 standard and TS edition.
Ok – so after you install the bits – fireup VS 2008 and create a new console application. Add a reference to the Microsoft.Contracts
library as shown below and insert:
using System.Diagnostics.Contracts
and
using System.Diagnostics
at the top of your program.
Just so we understand it clearly – let's write a class SimpleCalculate
and use our old friend Debug.Assert
to code defensively.
class SimpleCalculate
{
private int num1;
private int num2;
public SimpleCalculate(int numberone, int numbertwo)
{
num1 = numberone;
num2 = numbertwo;
}
public int Divide()
{
Debug.Assert(num2 > 0, "numbertwo should be greater than 0");
if (num2 > 0)
return num1 / num2;
return num1;
}
}
And our console app will look like:
class Program
{
static void Main()
{
SimpleCalculate sc = new SimpleCalculate(4, 0);
Console.WriteLine("Result is {0}", sc.Divide());
Console.ReadLine();
}
}
If we run this code – big surprise – Debug.Assert
will fire [if you build the project in debug mode] and will populate the following window:
Fine – this is a good enough solution. So why do we need anything else. Let’s rewrite the same class with code contracts.
class ClaculateWithContracts
{
private int num1;
private int num2;
public ClaculateWithContracts(int numberone, int numbertwo)
{
num1 = numberone;
num2 = numbertwo;
}
public int Divide()
{
Contract.Requires(num2 > 0);
if (num2 > 0)
return num1 / num2;
return num1;
}
}
So if you run this code as:
ClaculateWithContracts cc = new ClaculateWithContracts(4, 0);
Console.WriteLine("Result is {0}", cc.Divide());
Nothing will happen. In fact, because of the high quality of my code – output will be 4
. [i.e. this code will not break – that’s why I am an architect – I can write unbreakable code. Figure out why the output is 4
.]
The reason our contract is not working is because we need an additional step to use this contract. Right click on the project and go to the properties as shown below:
And from properties window, select Code Contract and check the perform runtime contract checking checkbox as shown below:
Now if you run the code again, our contract will hit. It will produce the following output:
Not much different than what Debug.Assert
did – correct? But wait a minute before you close the browser window... let me finish the story here. One important thing to notice is the timing when the assertion window is produced. Debug.Assert
will hit when you reach up to that condition, whereas pre condition failed window is populated as soon as ClaculateWithContracts cc = new ClaculateWithContracts(4, 0);
line is executed. You can check the call stack to confirm this claim.
Now the thing that sucks the most is that contract static checking is only available in VSTS, and I am using VS 2008 pro SP1. So I can't talk about that feature here. But it is a great way to harden your code.
Now a little bit of decoupling – comment out the line Contract.Requires(num2 > 0);
and add a special method – just type cim and VS code snippet will show up – hit the tab twice to insert the boiler plate code.
[ContractInvariantMethod]
protected void ObjectInvariant()
{
Contract.Invariant(this.num2>0);
}
Now if you run the program, you will get the following output:
So by doing this, we opened up a communication channel for ClaculateWithContracts
to express what is acceptable and what is not acceptable for it to work with. Again, if you trace the call stack – this window will pop up at the time of the instantiation of ClaculateWithContracts
.
Ok – you are still not convinced that this is any better than Debug.Assert
. So let's add one more thing – a money back guarantee that our method will always behave and will do the right thing and nothing else – all the time. WOW – what a baloney! Am I smoking something – I mean if the code will work right 100% of the time, then where is the job security? [if (U.MyBoss) please ignore; else continue;
]
Anyways, we can add a guarantee that our method will always return a non-zero result. Let's modify our method to implement this functionality.
public int Divide()
{
Contract.Ensures(Contract.Result<int />() > 0);
if (num2 > 0)
return num1 / num2;
return num1;
}
Notice the Contract.Ensures
, it means the result coming out of this method will always be greater than 0
. Just press ce to insert Contract.Ensures
snippet and inside it type crr to insert the contract result snippet. So now we have two way traffic – ClaculateWithContracts
is very clear about what is acceptable and what its public
methods will do. So if you call this type as:
ClaculateWithContracts cc = new ClaculateWithContracts(4, 8);
you will get a message like the one shown below explaining the postcondition failure:
Now for those who are paying close attention to this implementation – we have Contract.Ensures(Contract.Result<int>() > 0);
before the return statement and in fact the actual logic. So how does this contract work? I mean, if the logic is still not executed then how come this code is evaluating the end result? Magic – not at all.
You have reached upto this point only proves your determination to learn new technology. So please go ahead and figure out this last missing link. Let me know the answer on 1800 call abhi!
Happy programming!
History
- 12th August, 2009: Initial post