About 6 months ago, I briefly tried out JetBrains IntelliJ. As far as Java development goes, there doesn't appear to be a more impressive IDE. I had heard of JetBrains ReSharper for Visual Studio at that point but I hadn't tried it out. Needless to say, once you've given ReSharper a go there's just no going back.

When the ReSharper 4.0 EAP was announced I started testing it out. I did my bit for JetBrains and submitted bug reports when issues popped up. When it was finally released, I ordered my copy.

ReSharper 4.0 is packed with useful features. One of the new features that caught my eye is the Annotated Framework. On its own, the Annotated Framework doesn't appear as significant as the many other features provided. It's the last feature documented right down at the bottom of the Code Analysis feature page on the JetBrains site. But in terms of software development practices, it's an interesting indication of what direction JetBrains see developers taking to improve the quality of their code.

What is the Annotated Framework?

The Annotated Framework is contained in the JetBrains.Annotations namespace and consists of the following custom attributes (as described on the JetBrains web site).

  • StringFormatMethodAttribute (for methods that take format strings as parameters)
  • InvokerParameterNameAttribute (for methods with string literal arguments that should match one of caller parameters)
  • AssertionMethodAttribute (for assertion methods)
  • AssertionConditionAttribute (for condition parameters of assertion methods)
  • TerminatesProgramAttribute (for methods that terminate control flow)
  • CanBeNullAttribute (for values that can be null)
  • NotNullAttribute (for values that can not be null)

The idea is that you use these attributes to decorate your methods and parameters so that ReSharper can provide you with better live code analysis. For example, the code below shows a custom method called MyFormat that has the same signature as String.Format. This method uses composite formatting which means it takes a string that contains any number of format items (like {0}, {1}, etc.) in addition to that many parameters, each of which corresponds to a format item.

[StringFormatMethod("text")]
public void MyFormat( [NotNull] string text, params object[] args )
{
    // Output the text specified.
}

The method signature above is decorated with some attributes from the JetBrains.Annotation namespace. The first is a method attribute, StringFormatMethod and it takes a single parameter. The parameter is used to specify the name of the parameter in the method call that contains the composite format string. In this case, the string is called "text". The second is a parameter attribute, NotNull. This attribute is used to indicate that the parameter it decorates should never be null.

When you make calls to the MyFormat method, ReSharper will inform you of any instances where your code is not complying with the requirements of these attributes. Below is a usage example.

public void TestMethod()
{
    int i = 0;
    int j = 0;
 
    // The call to MyFormat below is flagged by ReSharper as containing problems
    // because it has two format items, but only one additional paramter.
    MyFormat( "{0}, {1}", i );
 
    // The call to MyFormat below is flagged by ReSharper as containing problems
    // because the composite format string parameter is null.
    MyFormat( null, i, j );
    
    // The call to MyFormat below is not flagged because the composite format string 
    // is not null and both format items are accounted for in the parameters i and j.
    MyFormat( "{0}, {1}", i, j );
}

In addition to being able to use these attributes in your own code, JetBrains have annotated most of the .NET Framework so you get a nice benefit there also.

To use the code annotation attributes in your own code, you can either add a reference to the JetBrains.Annotations.dll (found in the ReSharper install directory) or, copy the default implementation straight into your project.

The key point to keep in mind about the Annotated Framework is that it is designed to give you better code analysis. There are no runtime implications here, in other words no exceptions will be thrown if a parameter you've annotated with the NotNullAttribute ends up containing a null value.

But wouldn't it be nice if the Annotated Framework did allow you to enforce runtime constraints? Spec# (from Microsoft Research) has this facility and more. Check Scott Hanselman's podcast on Spec# for more info.

As it is the Annotated Framework looks like a step towards Design by Contract for C# developers.

Design by Contract

According to Wikipedia, Design by Contract is an approach to software design whereby 'software designers should define precise verifiable interface specifications for software components based upon the theory of abstract data types and the conceptual metaphor of a business contract.'

For a method on a class object, this boils down to the following.

  1. Specifying a precondition for the method. The caller of the method is obliged to meet this precondition and this frees the method from having to handle the precondition.
  2. Specifying a postcondition for the method. The method will guarantee this postcondition on exit. This frees the caller from having to handle the postcondition.
  3. Specifying an invariant. The method assumes this value on entry and guarantees it on exit.

The extent to which C# currently supports Design By Contract natively is type checking. For example, the code below shows a method that allows the caller to set an email address.

public void SetEmail( string email )
{
    // Store the email address.    
}

The contract being enforced by C# natively for this method guarantees that the email parameter must be a string object. But an email address is more than just a string. It's a string that contains characters in a specific pattern. In the code below I've made the contract less vague with a fictitious Regex attribute.

public void SetEmail( [Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")] string email )
{
    // Store the email address.
}

In the code above I've made the contract explicit. It implies that the method should only accept strings that contain valid email addresses that match the specified regular expression for an email address. This requirement is not buried inside the method body.

I've read some interesting blog posts recently describing different approaches to enforcing contracts as described above. Fredrik Normén and Roger Alsing have both written about this topic.

Extending the Annotated Framework

As a test, I decided to try and extend the annotated framework so that it also provides run-time checking. There are a number of difficulties with the idea of enforcing contracts with attributes at run-time using the current version of C#. Although you can use reflection to get details about the parameters of a method, it is not possible to use this approach to retrieve the value of these parameters at run-time. If you could get at these values easily it would mean you could decorate your methods to describe a contract and then assert the contract with a simple call to an contract method as shown below.

public void SetEmail([Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")] string email)
{
    Contract.Demand();
    
    // Continue with method body
}
 
public static class Contract
{
    public static void Demand()
    {
        var stack = new StackTrace(false);
        var frame = stack.GetFrame(1);
        var method = frame.GetMethod();
 
        foreach (var parameter in method.GetParameters())
        {
            foreach (var attribute in parameter.GetCustomAttributes(false))
            {
                var validator = attribute as ValidatorAttribute;
                if( validator != null)
                {
                    validator.Validate(parameter.Name, parameter.Value); // NOTE: parameter.Value is a fictitious property.
                }
            }
        }
    }
}

The code above assumes that all Custom Validation Attributes derive from a ValidatorAttrbiute class whose interface contains a method called Validate. It also uses a fictitious property of the ParameterInfo object parameter.

To get the above code to compile and run, I had to pass in the parameter values and remove the reference to the fictitious ParameterInfo Value property as shown below.

public void SetEmail([Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*")] string email)
{
    Contract.Demand( email ); // Pass in the method parameters.
 
    // Continue with method body        
}
 
public static class Contract
{
    public static void Demand(params object[] parameters)
    {
        var stack = new StackTrace(false);
        var frame = stack.GetFrame(1);
        var method = frame.GetMethod();
 
        var parameterIndex = 0;
        foreach (var parameter in method.GetParameters())
        {
            foreach (var attribute in parameter.GetCustomAttributes(false))
            {
                var validator = attribute as ValidatorAttribute;
                if( validator != null)
                {
                    validator.Validate(parameter.Name, parameters[parameterIndex]);
                }
            }
            parameterIndex++;
        }
    }
}

This requires that all the parameters appear in the call to Contract.Demand, and they must occur in the same order as the containing method. Apart from the performance issues that come with using reflection, the approach I've tested above is just not as clean as other simpler approaches to contract validation. And it doesn't come close to what can be done with Spec#.

Conclusion

The new ReSharper Annotated Framework does exactly what it's supposed to. It improves code analysis. It also encourages a Design by Contract approach to software development. In effect, it offers a first line of defense against vague interfaces and focuses the developer on establishing expectations before and after method calls. It will be interesting to see if, or how this influences the C# community in general and also how this in turn influences Microsoft when advancing the C# language. Let's hope that Microsoft Research get the chance to have Spec# improvements integrated into C#.

You can find out more about ReSharper 4.0 at the JetBrains web site.