Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Introducing Code Contracts

0.00/5 (No votes)
25 Aug 2010 2  
Using Code Contracts to make elegant code

Introduction

How many times have you written methods where you end up bunging in a load of conditional tests up front to make sure that inputs are valid? You normally end up with a bunch of code that looks like this:

public void Initialize(string name, int id)
{
    if (string.IsNullOrEmpty(value))
        throw new ArgumentException("name");
    if (id < 0) 
        throw new ArgumentOutOfRangeException("id");
    // Do some work here.
}

While I applaud your diligence and true professionalism, doesn't code like this just smell awful to you? It certainly does to me, and it really seems to clutter methods up. Wouldn't it be great if we could set up some form of contract that mapped this out for us? Wouldn't it be nice if we had something that actually set up some pre and post conditions on the method calls? Wouldn't it be great if we had a Code Contract? Well, those nice people at Microsoft certainly think so and have helpfully provided us with the fruits of their labours based on their research in Spec#.

The Basics

Contracts basically fall into two categories; preconditions and postconditions. A precondition states that certain things must be true before a method can execute, and a postcondition states that certain things must be true after a method has executed. So far so good, and pretty handy.

Let's look at an example of this in operation:

public void Initialize(string name, int id)
{ 
    Contract.Requires(!string.IsNullOrEmpty(name));
    Contract.Requires(id > 0);
    Contract.Ensures(Name == name);
    Contract.Ensures(Id = id); 
    // Do some work here.
} 

This simple method has two preconditions (expressed using Contract.Requires) and two postconditions (expressed using Contract.Ensures). I like the clarity of the syntax here, it's clear that these form part of the contract (and Code Contracts can automatically create XML documentation directly from your code).

Some things that you should be aware of here; the contract must be specified before you attempt to do any work in the method; if you're not careful you don't get to choose what exception is thrown by the contract (you need to use the appropriate generic, e.g. Contract.Requires<ArgumentOutOfRangeException>); and you need to download a binary rewriter to actually use the contracts at runtime (called ccrewriter) from Dev Labs - it comes complete with a handy VS add in that makes working with ccrewriter a lot nicer; accessible from a really useful property page where you trigger ccrewriter by specifying that you want to perform runtime contract checking.

CodeContractsPropertyPage.png

Now, if I call this method and pass in an invalid value (such as an Id of 0), I should trigger the contract failure:

PreconditionExceptionInInterfaceContract.png

Now for the Useful Stuff

While this is all handy-dandy, there's so much more that Code Contracts can do. How about setting up an interface and having it so that the contracts are applied whenever you use the interface? Dagnabit, but that sounds good to me, and I bet it sounds good to anybody who's busy writing frameworks.

"Surely you jest Pete" I hear you say. I jest you not - this is easily achieved using Code Contracts, and here's how it's done. First of all, you define an interface. Let's set one up that we can use:

public interface IUseful
{ 
    void Initialize(string name, int id);
} 

Then we set up an abstract class that we use to actually define the contract:

public abstract class UsefulContract : IUseful
{ 
    public void Initialize(string name, int id)
    {
        Contract.Requires(!string.IsNullOrEmpty(name));
        Contract.Requires(id > 0);
        Contract.Ensures(Name == name);
        Contract.Ensures(Id = id);
    }
} 

Now, we need to decorate the interface to tell it that we have a class that forms the contract. We need to use the ContractClassAttribute attribute:

[ContractClass(typeof(UsefulContract))]
public interface IUseful

Then, we need to decorate the actual contract implementation to tie it back to the interface:

[ContractClassFor(typeof(IUseful))]
public abstract class UsefulContract : IUseful  

Now, whenever we use the interface, the contract is automatically applied.

What about Performance?

The beauty of Code Contracts is that they don't rely on reflection to perform their magic, the binary rewriter transforms the contract into runtime code. If we take a look at the code that we specify for the Name property in the attached sample project, we see it looks like this:

public string Name
{
    get
    {
        return _name;
    }
    set
    {
        if (_name == value) return;
        OnChanging("Name");
        _name = value;
        OnChanged("Name");
    }
}

The contract was set up in the contract class like this:

public string Name
{
    get
    {
        return string.Empty;
    }
    set
    {
        Contract.Requires(!string.IsNullOrEmpty(value), 
            "The name must be greater than 0 characters long.");
    }
}

Now, with the beauty of Code Contracts, this translates into the following runtime code:

public string Name
{ 
    get
    { 
        return this._name;
    }
    set
    {
        __ContractsRuntime.Requires(!string.IsNullOrEmpty(value), 
            "The name must be greater than 0 characters long.", 
            "!string.IsNullOrEmpty(value)");
        if (this._name != value)
        {
            this.OnChanging("Name");
            this._name = value;
            this.OnChanged("Name");
        }
    }
} 

Conclusion

I hope that I've whetted your appetite to go out and play with code contracts. The more I use them, the more I like them.

Part 2 of this article is now available here.

History

  • 23/08/10 - Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here