The jQuery Chaining Pattern Implemented Using C#

If you are a web developer you surely are familiar with jQuery and its ability to chain commands together. For instance:

$("#someElement")  // Select an element
    .removeClass("off")  // Remove a class
    .css("background" : "red")  // Add a style
    .append("<span>This element is now red.</span>");  // Append new elements

Why does this work? Each of the jQuery operations returns another jQuery object. Therefore the result of each operation is used as the initial state of the following operation. This is a very powerful pattern and one that we can replicate in C#.

Extension Methods

One of the features that was added to C# 3.0 was extension methods. From MSDN:

Extension methods enable you to ‘add’ methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.

Let’s look at a concrete example:

public static string ConvertMonthToSeason(this int month)
{
    switch (month)
    {
        case 1:
        case 2:
        case 3:
        case 4:
        case 11:
        case 12:
            return "Winter";
        default:
            return "Construction";
    }
}

The above code is a static method converts a month to a given season (we only have those two seasons in Wisconsin). Take a closer look at that input parameter. Notice the ‘this’? That is how you create an extension method. Now we can use the extension method just like it was a native method on the int type. This can be seen in the following intellisense:

image

Here is another example of an extension method:

public static string ReverseTheString(this string input)
{
    char[] arr = input.ToCharArray();
    Array.Reverse(arr);
    return new string(arr);
}

This is a string extension method that reverses the characters of the provided string. So the following code will reverse the characters in my name:

const string myName = "Bob Cravens";
string myNameReversed = myName.ReverseTheString();

Notice that the first extension method took an integer as a parameter and returned a string. The second extension method took a string as a parameter and returned another string. We could chain these two methods if we wanted. That would look like the following:

const int month = 1;
string seasonReversed = month.ConvertMonthToSeason().ReverseTheString();

Chaining With A Purpose

The chaining introduced above is very simple. It is not designed with the intent of chaining as found in the jQuery library. That type of chaining is very purposeful. In jQuery we chain operations many times to filter our selections. So what would be a good purpose for chaining in C#?

How many times have you written code like the following?

public void TakesParameters(string fileName, int age)
{
    if (string.IsNullOrEmpty(fileName))
    {
        throw new ArgumentException("fileName");
    }
    if (!File.Exists(fileName))
    {
        throw new FileNotFoundException(fileName);
    }
    if (age < 21)
    {
        throw new ArgumentOutOfRangeException("age", "must be at least 21");
    }

    // Do something with the parameters....
}

You have a method that takes parameters and, like the good programmer you are, you write validation code to ensure the parameters are what you expected. It seems like the same validation code….”make sure the string is not null or empty”….”ensure the file exists”…is written at the top of many methods. Doesn’t this sound like a good place for refactoring? Let’s try out our extension methods. Check out the following extension methods:

public static string IsNotNullOrEmpty(this string input, string parameterName)
{
    if(string.IsNullOrEmpty(input))
    {
        throw new ArgumentException(parameterName);
    }
    return input;
}

public static string FileExists(this string fileName)
{
    if(!File.Exists(fileName))
    {
        throw new FileNotFoundException(fileName);
    }
    return fileName;
}

public static int IsNotLessThan(this int value, int maxValue, string parameterName)
{
    if(value<maxValue)
    {
        throw new ArgumentOutOfRangeException(parameterName, "must be at least " + maxValue);
    }
    return value;
}

Now I can refactor my method that takes parameters into the following:

public void TakesParameters(string fileName, int age)
{
    fileName.IsNotNullOrEmpty("fileName").FileExists();
    age.IsNotLessThan(21, "age");

    // Do something with the parameters....
}

Isn’t that much simpler? Not only that I can simplify validation code in a lot of other methods by reusing these extension methods. There are a couple of problems with the above code.

First my extension methods for validation are cluttering up the namespace (and intellisense) of the type that I am extending. This is not a big deal so far, but what if we wanted to extend the validation extension methods to cover many more options? Soon we would end up with extension method soup.

Second, the resulting code is simpler but not necessarily fluent. It may not be obvious that “IsNotNullOrEmpty” is a validation extension method that throw exceptions. Yes, we can (and should) capture this in the XML documentation for that method. But the code could still stand a bit more clarity.

An Awesome Example Of Chaining

If you are excited about the above code, you have to check out the CuttingEdge.Conditions library on the Codeplex site. The library is written by Steven van Deursen. The CuttingEdge.Conditions library provides a reusable, fluent and simple way to validate your inputs. In addition, it provides an elegant solution to the namespacing and fluent problems. How are these issues solved?

A generic wrapper type is introduced that is a container for the parameter. Please go to the Codeplex site to look at the exact code. The following is a simplified version of the generic wrapper that is used in CuttingEdge.Conditions:

public class WrapperType<T>
{
    public readonly T Value;
    public readonly string ParameterName;

    public WrapperType(T value, string parameterName)
    {
        Value = value;
        ParameterName = parameterName;
    }
}

This wrapper takes the original value as a generic input parameter and a parameter name in the constructor and simply copies this info to local variables. Extension methods on this generic wrapper are written that then provide the validation. This is a really clever way to not clutter up the original type’s namespace and it also provide a mechanism to make the validation calls more fluent. Take a look at the above validation refactored to use the generic wrapper class:

public static class Validate
{
    public static WrapperType<T> Parameter<T>(T value, string parameterName)
    {
        return new WrapperType<T>(value, parameterName);
    }

    public static WrapperType<string> IsNotNullOrEmpty(this WrapperType<string> input)
    {
        if(string.IsNullOrEmpty(input.Value))
        {
            throw new ArgumentException(input.ParameterName);
        }
        return input;
    }

    public static WrapperType<string> FileExists(this WrapperType<string> fileName)
    {
        if(!File.Exists(fileName.Value))
        {
            throw new FileNotFoundException(fileName.Value);
        }
        return fileName;
    }

    public static WrapperType<int> IsNotLessThan(this WrapperType<int> input, int maxValue)
    {
        if(input.Value<maxValue)
        {
            throw new ArgumentOutOfRangeException(input.ParameterName, "must be at least " + maxValue);
        }
        return input;
    }
}

There is an additional static method (not an extension method) that constructs a wrapper instance provided a generic value and parameter name. Then follows three extension methods that perform the validation that we had earlier. Notice that the extension methods are now extending the wrapper class. Now the method that requires parameters can be refactored to use these new validation extension methods. This code now looks like the following:

public void TakesParameters(string fileName, int age)
{
    Validate.Parameter(fileName, "fileName")
        .IsNotNullOrEmpty()
        .FileExists();

    Validate.Parameter(age, "age")
        .IsNotLessThan(21);

    // Do something with the parameters....
}

This code is as simple (okay a tiny bit more verbose) as the last refactoring, but now the intent is much more fluent. By looking at the code, you understand that validation is being performed on the parameters.

Summary

Using C# extension methods it is possible to develop a framework that allows the type of chaining familiar to jQuery users. The CuttingEdge.Conditions library is a great example of a validation library that leverages the chaining concept.

Tags:,
No Responses

Leave a Reply

Your email address will not be published.

*