Thursday 18 July 2013

Make your code readable by making it flow with Generics

I’ve seen a couple of examples of code recently which basically have a method which work primarily on a base class but the resultant will always be cast to a concrete implementation. This can make the code a bit clunky as each caller has to cast the resultant to the type it’s expecting. Let me show you want I mean:

public abstract class Base
{
    public string Comment { get; set; }
}

public class Concrete : Base
{
}

public class Update
{
    public static Base AddComment(string message)
    {
        // the type created can be determined by some other means eg db call etc.
        var response = new Concrete();
        response.Comment = message;
        return response;
    }
}

And then when it is called it needs to cast to the required type:

var concrete = (Concrete) Update.AddComment("update the comment");

This code snippet doesn’t read that badly however once the system gets bigger or this technique is used for more complicated types/systems then it can start to look clunky. As you know what types you’ll be working with and what you will expect returned when calling the code then you can make the code clearer and flow by using generics.

public class Update
{
    private static Base AddComment(string message)
    {
        // the type created can be determined by some other means eg db call etc.
        var response = new Concrete();
        response.Comment = message;
        return response;
    }

    public static T AddComment<T>(string message) where T : Base
    {
        // in this example the call is into the original method
        // but this does not have to be the case
        return (T) AddComment(message);
    }
}

Notice I’ve made the original AddComment method private as I don’t want to allow any callers access to it directly. The example calls into the original private method but this does not have to be the case.

Now when the same functionality is called in the main program flow it looks like this:

var concrete = Update.AddComment<Concrete>("update the concrete");

Updating the API in this way makes the calling code clearer to read and makes the API signature developer friendly so a potential cast is not missed out.