Click here to Skip to main content
15,886,055 members
Articles / Programming Languages / Visual Basic

CuttingEdge.Conditions

Rate me:
Please Sign up or sign in to vote.
4.59/5 (19 votes)
23 Jun 2011MIT3 min read 125K   67   84   43
A pre- and postcondition validation framework based on .NET 3.5 extension methods

Introduction

CuttingEdge.Conditions is a library that helps developers to write pre- and postcondition validations in their C# 3.0 and VB.NET 9 code base. Writing these validations is easy and it improves the readability and maintainability of code.

Dependency

CuttingEdge.Conditions is language independent and can be used with both C# 3.0 and VB9. The library can be run on machines that do not have .NET 3.5 installed. While the CuttingEdge.Conditions.dll assembly itself has a dependency on System.Core (.NET 3.5), users can safely add it to their .NET 2.0 projects (as long as the C# 3.0 or VB9 compilers are used).

Conditions

Writing precondition validations raises the quality of code. Code with validations is easier to understand and allows developers to find bugs faster, mostly during development instead of during debugging. Writing precondition validations however has always been the poor relation in programming. It takes time to write it and many developers I worked with (even the ones I respect) skipped writing them.

Skipping precondition validations will lead to code that is more difficult to use and is likely to be misused. It allows developers to pass invalid method arguments, which results in unexpected program behavior and those awful NullReferenceExceptions from deep down the call stack. It leads to a higher amount of bugs and thus more time spent debugging.

The CuttingEdge.Conditions library is an attempt to lower the barrier of writing precondition validations and make code more readable, thus resulting in better code, less bugs, and shorter development cycles.

To understand how CuttingEdge.Conditions tries to achieve this, let us first have a look at some code we might write on a daily basis. Here is an C# example of precondition validations, the old fashioned way:

C#
void TheOldFashionWay(int id, IEnumerable<int> collection, DayOfWeek day)
{
    if (id < 1)
    {
        throw new ArgumentOutOfRangeException("id", String.Format(
            "id should be greater than 0. The actual value is {0}.", id));
    }
    if (collection == null)
    {
        throw new ArgumentNullException("collection", 
            "collection should not be empty");
    }
    if (collection.Count() == 0)
    {
        throw new ArgumentException("collection should not be empty", 
            "collection");
    }
    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Friday)
    {
        throw new InvalidEnumArgumentException(String.Format(
            "day should be between Monday and Friday. " +
            "The actual value is {0}.", day));
    }

    // Do method work
}

That’s an awful amount of code for a few simple validations! Here’s how it looks if CuttingEdge.Conditions would be adopted:

C#
void TheConditionsWay(int id, IEnumerable<int> collection, DayOfWeek day)
{
    Condition.Requires(id, "id").IsGreaterThan(0);
    Condition.Requires(collection, "collection").IsNotEmpty();
    Condition.Requires(day, "day").IsInRange(DayOfWeek.Monday, DayOfWeek.Friday);

    // Do method work
} 

That’s quite different, isn't it? It’s not only far less code; it’s also very readable. And please note that both methods have exactly the same contract. Both methods throw exactly the same exceptions and exception messages!

Besides these normal precondition checks, CuttingEdge.Conditions enables you to do postcondition checks as well. Unlike a precondition, the violation of a postcondition has purely an internal cause. It can be considered a bug. Throwing an ArgumentException in that case would clearly confuse the developer using that code. Because of this difference, CuttingEdge.Conditions will always throw a PostconditionException on a violation of a postcondition.

Here is an example of a postcondition check:

C#
public ICollection PostconditionExample()
{
    object obj = Activator.CreateInstance(typeof(Collection<int>));

    Condition.Ensures(obj, "obj").IsNotNull().IsOfType(typeof(ICollection));

    return (ICollection)obj;
} 

The postcondition example shows two interesting things. Firstly, The Ensures extension method is used to start a postcondition validation. Secondly, method calls can be chained in a fluent manner as shown with the IsNotNull and IsOfType methods.

The API

The CuttingEdge.Conditions API has many validation methods that easily cover 99% of your validation needs. There are currently 412 extension methods for 53 different checks. The API can be divided in eight groups: 

  • Entry point methods
  • Null check methods
  • Type check methods
  • Comparison checks
  • Collection checks
  • String checks
  • Numeric checks
  • Evaluations

The number of methods will possibly grow over time, and please comment here, on my blog or on CodePlex if you think there are validations missing. I will consider adding them to the library. Also note that it’s easy for you to extend the API with your own methods, by simply placing extension methods in your own project. For more information on extending CuttingEdge.Conditions, please read the Extending CuttingEdge.Conditions wiki on CodePlex.

More Information

This third stable release of the CuttingEdge.Conditions library has just been released. You can download the source and runtime library from CodePlex. Please visit conditions.codeplex.com or my blog.

Happy validating!

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer (Senior)
Netherlands Netherlands
I'm a freelance developer from the Netherlands, working with .NET technology on a daily basis, and officially diagnosed as a workaholic.

Comments and Discussions

 
GeneralNice but .. Pin
Guido_d16-Feb-10 5:44
Guido_d16-Feb-10 5:44 
GeneralRe: Nice but .. Pin
VCSKicks16-Feb-10 5:51
VCSKicks16-Feb-10 5:51 
GeneralRe: Nice but .. Pin
The .NET Junkie16-Feb-10 6:43
The .NET Junkie16-Feb-10 6:43 
GeneralRe: Nice but .. Pin
Paul Selormey23-Jun-11 15:03
Paul Selormey23-Jun-11 15:03 
GeneralNice! Pin
Jason Law9-Sep-09 14:38
Jason Law9-Sep-09 14:38 
QuestionEnsuresWhileDebugging Pin
Alexey Romanov7-Aug-08 0:04
Alexey Romanov7-Aug-08 0:04 
AnswerRe: EnsuresWhileDebugging [modified] Pin
The .NET Junkie6-Sep-08 6:32
The .NET Junkie6-Sep-08 6:32 
GeneralRe: EnsuresWhileDebugging Pin
Member 145294324-Jun-11 1:33
Member 145294324-Jun-11 1:33 
GeneralRe: EnsuresWhileDebugging Pin
The .NET Junkie24-Jun-11 3:53
The .NET Junkie24-Jun-11 3:53 
GeneralWhy not design by contract Pin
danidanidani31-Jul-08 3:15
danidanidani31-Jul-08 3:15 
AnswerRe: Why not design by contract [modified] Pin
The .NET Junkie31-Jul-08 3:44
The .NET Junkie31-Jul-08 3:44 
GeneralRe: Why not design by contract Pin
danidanidani31-Jul-08 3:52
danidanidani31-Jul-08 3:52 
QuestionLinFu? Pin
Judah Gabriel Himango21-Jul-08 9:22
sponsorJudah Gabriel Himango21-Jul-08 9:22 
AnswerRe: LinFu? [modified] PinPopular
The .NET Junkie23-Jul-08 0:53
The .NET Junkie23-Jul-08 0:53 
Hi Judah,

Thank you for pointing at LinFu. The Design by Contract part of the LinFu library is very interesting and Philip Laureano has written a great article (I rewarded the article with a vote of 5). Both CuttingEdge.Conditions and LinFu.DesignByContract2 will give you the same result, but they differ quite a bit in getting to that result.

They quite look a like in a way that both frameworks are trying to get Design by Contract (DbC) to the mainstream programmer. Both frameworks can be used in defining preconditions and postconditions. LinFu also has the possibility to define invariants invariants . With CuttingEdge.Conditions you can’t (yet. I'm considering this!). I'd like to see DbC as a compiler verified mechanism, so in that sense I believe neither of them really do DbC (I rather see them as defensive programming tools). Both are only able to verify the checks during runtime (yes, that's why we really need Spec#).

The big difference between the two is how developers should work with it. One of the main requirements for CuttingEdge.Conditions, is that the barrier for developers in using the framework should be as low as possible. CuttingEdge.Conditions should be as easy to use as possible. LinFu is a great framework, but it isn't easy. I like how it uses [attributes] in defining the contracts, but it requires a lot of code to define even the simplest validations. Besides that, it uses an Inversion of Control (IoC) mechanism to enable wrapping the real objects with proxies to enable the validation. IoC is great, but it depends on the project’s needs and the skill of the developers if you’re willing to walk that path. Besides that, the code you write has to be designed for LinFu (read: everything must be virtual / overridable or have an interface).

Another difference between the two is that CuttingEdge.Conditions plays by the rules of the Framework Design Guidelines (FDG) by always throwing an ArgumentException when a precondition fails. LinFu.DesignByContract2 throws a PreconditionException. This allows you to use CuttingEdge.Conditions for reusable frameworks, while LinFu.DesignByContract2 is limited to internal libraries and end user applications (when playing to the rules of the FDG, that is).

By using attributes to define the contracts, LinFu.DesignByContract2 uses in fact Aspect Oriented Programming (AOP). This allows you to keep your code very clean and even add contracts later on (without altering your code), or even at runtime. It’s even possible to add validation to code you don’t own (still this support is limited, because everything you want to validate, must be virtual or have an interface). These are all things that simply can’t be done with CuttingEdge.Conditions.

CuttingEdge.Conditions only supports validations to be written inside the method that has to be validated. With LinFu, validations can be written everywhere, except within the method that has to be validated. This is a big difference, that has to be taken into consideration. Of course, from an AOP perspective, it wouldn’t make sense to define those validations inside the method itself.

LinFu also has a more natural way of writing validations, a bit like CuttingEdge.Conditions does. But, because LinFu doesn’t allow you to write those validations within the actual method, those two are actually hard to compare. Still, the two examples below, could give you some idea in how the syntaxes look on the two frameworks, while doing the same validation:

LinFu Example on C# 3.0:
Ensure.On(contract)
	.ForMethodWith(m => m.Name == "Open")
	.That(c => c.State == ConnectionState.Open)
	.OtherwisePrint("The connection failed to open!");

CuttingEdge.Conditions on C# 3.0:
Condition.Ensures(connection.State)
	.IsEqualTo(ConnectionState.Open, "The connection failed to open!");

Please don't get me wrong. I think LinFu is great and it is much more powerful than CuttingEdge.Conditions will ever be, and again, I really like the declarative way of defining contracts with attributes! However, adding LinFu.DesignByContract2 to a project is a major design decision and can't be taken lightly, while adding CuttingEdge.Conditions is practically for free, but is more limited in use and doesn't play by the rules of IoC and AOP.

I’ve told you how the two frameworks are different. Which one is better on the project you work on is for you to decide.


Generalmaybe idea Pin
Mr.PoorEnglish17-Jul-08 21:48
Mr.PoorEnglish17-Jul-08 21:48 
GeneralOne more question Pin
Mr.PoorEnglish17-Jul-08 22:40
Mr.PoorEnglish17-Jul-08 22:40 
GeneralRe: One more question Pin
The .NET Junkie20-Jul-08 10:04
The .NET Junkie20-Jul-08 10:04 
GeneralRe: One more question Pin
Mr.PoorEnglish20-Jul-08 11:35
Mr.PoorEnglish20-Jul-08 11:35 
GeneralRe: One more question Pin
The .NET Junkie20-Jul-08 12:29
The .NET Junkie20-Jul-08 12:29 
GeneralRe: One more question Pin
Mr.PoorEnglish20-Jul-08 23:58
Mr.PoorEnglish20-Jul-08 23:58 
GeneralRe: One more question Pin
The .NET Junkie21-Jul-08 4:38
The .NET Junkie21-Jul-08 4:38 
GeneralExtension methods on .net2.0 Pin
geo_m17-Jul-08 0:53
geo_m17-Jul-08 0:53 
AnswerRe: Extension methods on .net2.0 Pin
The .NET Junkie18-Jul-08 8:07
The .NET Junkie18-Jul-08 8:07 
GeneralRe: Extension methods on .net2.0 Pin
geo_m21-Jul-08 0:27
geo_m21-Jul-08 0:27 
GeneralRe: Extension methods on .net2.0 Pin
Qwertie6-Aug-08 11:04
Qwertie6-Aug-08 11:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.