Code Contracts
So apparently we’re meant to be getting support for code contracts in .NET 4.0 which is great. But why wait until then when you can go to http://research.microsoft.com/en-us/projects/contracts/ and grab it for VS2008 now :-)
Why code contracts?
“So, what’s the big deal with code contracts?” you might ask. How are contracts different to just a bunch of asserts? It’s a little too big to cover here, but contracts are intended to make your code more explicit, and thus a lot easier to test and verify (including at compile time) and more stable in that terms of behaviour as well.
Where this gets interesting is that you can define contracts on interfaces. So now, you can not only have an expectation that an inheriting class will implement all the methods and properties defined by the interface itself, but that the class will also ensure certain things occur (such as returning non null values for instance). You can also ensure that classes using the interface call the methods on it with specific expectations met (such as always providing non null parameters, etc).
Contracts on Interfaces!
So, I’ve just started playing around with this stuff now and I had a quick look at the sample for code contracts where interfaces are concerned. Here’s the code:
class Program
{
static void Main(string[] args)
{
var f1 = new FooImplementation1();
int r1 = f1.Foo(0);
Contract.Assert(r1 > 0);
IFoo f2 = new FooImplementation2();
int r2 = f2.Foo(1);
}
}
[ContractClass(typeof(IFooContract))]
interface IFoo
{
int Foo(int x);
}
[ContractClassFor(typeof(IFoo))]
class IFooContract : IFoo
{
int IFoo.Foo(int x)
{
Contract.Requires(x > 0);
Contract.Ensures(Contract.Result<int>() > 0);
throw new NotImplementedException();
}
}
public class FooImplementation1 : IFoo
{
public int Foo(int x)
{
return x;
}
}
public class FooImplementation2 : IFoo
{
/// <summary>
/// Bad implementation of IFoo.Foo which does not always satisfy post condition.
/// </summary>
int IFoo.Foo(int x)
{
return x - 1;
}
}
When you compile this, it will throw a few warnings at you:
The first warning relates to this line
int r1 = f1.Foo(0);
Which violates the contract that requires the parameter be greater than zero.
The second warning is related to the second IFoo implementation, where this method:
int IFoo.Foo(int x)
{
return x - 1;
}
can’t prove that it will return a value greater than zero. The compiler even makes a suggestion that the Requires contract should be that (x-1) > 0. Not bad.
As for the implementation, since we can’t put code in interface declarations the tool uses the [ContractClassFor] attribute to provide the contract implementations. What you will also note is that the contract class uses an explicit interface implementation and also uses the same ContractClassFor attribute to indicate that it is the contract implementation for IFoo. BTW, the return values from the contract class are completely ignored.
P.S. You can put contracts on abstract methods in base classes as well using the same technique.
That’s some very nice stuff, and we don’t even have to wait for the CLR v4.0 release. We can do this stuff today!