Welcome to Dave Sexton's Blog Sign in | Join | Help

ContractN on CodePlex

I've just released the first beta version of ContractN, which is a fully managed programming-by-contract framework that uses the CLR's built-in support for aspect-oriented programming (AOP), which provides a way to seamlessly and intuitively describe the required pre- and post-conditions of a type's contract.

I got the idea based on this blog post by Sasha Goldshtein; although, Sasha's implementation and that of ContractN have little in common other than their purpose.  I liked the way Sasha used dynamically-generated code, but other than that I wasn't satisfied having to create the extra stuff that was required to enforce conditions.

Advantages of ContractN

The real benefit of ContractN, IMO, is that there's no overhead in terms of setting up your classes or their consumers, and you don't have to worry about breaking encapsulation or having to create any supporting interfaces or classes.  You just need to derive an object from ContractN.ProgrammingByContract. (It's a shame that this is required though - I hope AOP is eventually introduced as a C# language feature; although, I suspect that the CLR would have to participate as well to alleviate the need for subclassing.)

ProgrammingByContract is an abstract base class that sets up the AOP infrastructure, which is used to intercept method invocations and define conditions as attributes.  After defining a class that inherits from ProgrammingByContract, simply add the appropriate attributes wherever you'd like to enforce certain conditions on the public contract of your type.  Here's a really simple C# 3.0 example:

public class Person : ContractN.ProgrammingByContract
{
  [InRequired, OutRequired]
  public string Name { get; set; }
}

The example illustrates that there are some built-in conditional attributes for basic argument checking, such as InRequiredAttribute, OutRequiredAttribute and ReturnRequiredAttribute, which throw an exception when an argument (or in the case of the latter two, output parameters and a return value) are null.  I plan to add more conditions in the future, and the framework was designed to be flexible enough so that you can define your own conditions as well.

Custom Conditions

To define a new condition, create a class that derives from either PreConditionBaseAttribute, PostConditionBaseAttribute or ConditionBaseAttribute and override the abstract members.  Usage should be intuitive depending upon the implementation that you need, but you can look at the source code for InRequiredAttribute (beta 1) as an example.

Dynamic Conditions

I decided to take a different approach than Sasha in terms of how dynamic conditions are implemented.  I wanted to take advantage of static type checking instead of hard-coding constraints as strings.  PreConditionAttribute and PostConditionAttribute allow you to specify a method name on the decorated type that will be invoked automatically whenever any public method is called.  That also includes constructors and accessors for properties and events.  (Note that these attributes are also valid on a property, constructor, method or event.)  The method signature can vary depending upon your needs; generally it will be a parameterless instance method, though static methods are allowed as well.  The types of arguments that are accepted encapsulate information about a particular invocation.  For example, you could define a method that accepts an argument typed as ContractN.PropertyCall and the method will be invoked automatically whenever a property get or set accessor is invoked, pre- or post-invocation depending upon the attribute used.  Within these methods you can write code that will actually be part of the class that it's meant to constrain, which maintains encapsulation, makes it easy to share code between constraints and allows access to state with compiler support.

Here's a more sophisticated example than above.  It makes use of pre- and post-conditions described above and also implements ad-hoc conditions by providing an implementation of ICondition:

[PreCondition("TestStatic")]
[PreCondition("TestInstance")]
class AdvancedFeatures : ProgrammingByContract, ICondition
{
    #region Public Properties
    public string TestProperty { get; set; }
    #endregion

    #region Methods
    private static void TestStatic(PropertyCall info)
    {
        Console.WriteLine("Pre Static Property: {0}", info);
    }

    private static void TestStatic(MethodCallBase info)
    {
        Console.WriteLine("Pre Static Default: {0}", info);
    }

    private void TestInstance(MethodCallBase info)
    {
        Console.WriteLine("Pre Instance Default: {0}", info);
    }

    public void NoOperation()
    {
    }
    #endregion

    #region IPreCondition Members
    void IPreCondition.Apply(ConstructorCall info)
    {
        Console.WriteLine("Pre: {0}", info);
    }

    void IPreCondition.Apply(MethodCall info)
    {
        Console.WriteLine("Pre: {0}", info);
    }

    void IPreCondition.Apply(PropertyCall info)
    {
        Console.WriteLine("Pre: {0}", info);
    }

    void IPreCondition.Apply(EventRegistrationCall info)
    {
        Console.WriteLine("Pre: {0}", info);
    }
    #endregion

    #region IPostCondition Members
    void IPostCondition.Apply(ConstructorCall info, MethodCallReturn returnInfo)
    {
        Console.WriteLine("Post: {0}", info);
    }

    void IPostCondition.Apply(MethodCall info, MethodCallReturn returnInfo)
    {
        Console.WriteLine("Post: {0}", info);
    }

    void IPostCondition.Apply(PropertyCall info, MethodCallReturn returnInfo)
    {
        Console.WriteLine("Post: {0}", info);
    }
    
    void IPostCondition.Apply(EventRegistrationCall info, MethodCallReturn returnInfo)
    {
        Console.WriteLine("Post: {0}", info);
    }
    #endregion
}

When the above class is used as follows:

AdvancedFeatures features = new AdvancedFeatures();
features.TestProperty = "A test value";
features.NoOperation();

The console output is:

Pre Static Default: ContractN.ConstructorCall
Post: ContractN.ConstructorCall
Pre: ContractN.PropertyCall
Pre Instance Default: ContractN.PropertyCall
Pre Static Property: ContractN.PropertyCall
Post: ContractN.PropertyCall
Pre: ContractN.MethodCall
Pre Instance Default: ContractN.MethodCall
Pre Static Default: ContractN.MethodCall
Post: ContractN.MethodCall

One of the really neat uses for the PreConditionAttribute that I've found is to have ObjectDisposedException automatically thrown instead of having to check for it everywhere.  Here's an example that builds off of the Person class in my first example:

[PreCondition("NotDisposed")]
public class Person : ContractN.ProgrammingByContract, IDisposable
{
    [InRequired, OutRequired]
    public string Name { get; set; }

    private bool disposed;

    private void NotDisposed()
    {
        if (disposed)
            throw new ObjectDisposedException(this.GetType().FullName);
    }

    public void Dispose()
    {
        disposed = true;
    }
}

After the Dispose method is called, public members are no longer accessible to external types.  All calls will result in ObjectDisposedException automatically!

Conclusion

ContractN is more of a hobby project for me now than anything else, but it has potential and I'd really like to see it blossom into something useful.  If you have any suggestions for improvements please let me know and I'll consider them for the next beta release.  (I'm going to establish a timeline on-the-fly as I get ideas for features.)  I have some interesting ideas for new conditions and I hope to blog about them in the future, so don't wander too far off if you're interested...

Published Monday, March 10, 2008 5:23 AM by Dave Sexton
Filed under: , , , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: ContractN on CodePlex

While I am unfortunately not in a position at the moment to look at the source code for this project, I am curious as to what mechanism you are relying on, as I'm sure that many developers of AOP frameworks for .net would disagree with your claim regarding the "CLR's built-in support" for AOP. Which "built-in support" is this exactly?

Monday, March 10, 2008 12:11 PM by Jeremy Gray

# re: ContractN on CodePlex

The project's home page links to an article that provides details.  For your convenience, here's the link:

Aspect-Oriented Programming Enables Better Code Encapsulation and Reuse

http://msdn2.microsoft.com/en-us/magazine/cc301356.aspx

Note that the source code is available online:

http://www.codeplex.com/ContractN/SourceControl/ListDownloadableCommits.aspx

Monday, March 10, 2008 12:37 PM by Dave Sexton

# re: ContractN on CodePlex

Again, I've not had a chance to read the code, but based on the MSDN link you've provided, I should tell you that CBOs were long-ago eliminated as an option by the creators of basically every .net AOP framework because of the serious implementation constraints and performance overhead imposed by CBOs.

You've got a nice idea going here with your project, and I wouldn't want to see it die on the branch due to this, so just as a suggestion you might want to look into the various real AOP frameworks that are available for .net.

Monday, March 10, 2008 2:42 PM by Jeremy Gray

# re: ContractN on CodePlex

Thanks for the advice, I appreciate the concern; however, regardless of what every other .NET AOP project has done, ContractN's current implementation does its job nicely - I haven't run across any "serious implementation constraints" yet.  I think the reason is that the constraints of a CBO implementation, to which you are referring, are not really issues within the context of Programming-By-Contract.  For example, I'm OK with conditions being defined only on public members.

This is just a guess, but I bet that judicious use of design patterns could alleviate most, if not all, of the constraints that people might claim about CBOs anyway.

As for performance and memory usage, I'm not really concerned.  I plan to use this framework for defining business objects in real-world applications that run on desktop computers or web servers; i.e., there shouldn't be any noticeable difference before and after adding ContractN to an existing library with my intended usage.  Unless objects are being constructed in large quantities or in iterations, like a fly-wheel pattern, I think that using ContractN selectively will provide for an extremely simple yet effective way to introduce CLR-supported Programming-By-Contract designs into managed code.

Also, I doubt there's a more succinct and simple way to produce the current capabilities of ContractN using a third-party AOP framework.  ContractN, in its entirety, consists of only a single light-weight assembly that can be XCopy deployed.  That's a huge benefit IMO.

However, I'll do some research anyway to see what else is out there.  Would you care to provide a couple of references to some .NET AOP framework projects that I might be interested in researching?

Monday, March 10, 2008 3:25 PM by Dave Sexton

# re: ContractN on CodePlex

I'm not the one you asked, but the most interesting project in my eyes is http://www.postsharp.org/

Tuesday, September 23, 2008 11:46 AM by Andreas

Leave a Comment

(required) 
required 
Enter the word from the image above:
(6 characters)
(required)