Thom Lawrence

Entries tagged as ‘postcode’

Safety! Implicit Operator!

August 16, 2006 · No Comments

Despite all the effort involved, operator overloading in C# is a nice syntactic hug you should always try and give your code. While that usually just gets you a bunch of boring comparison operators which you are forbidden to use in interesting ways, there’s other stuff too. Obviously C#’s not quite as flexible as Ruby, where you just seem to be able to mash the keyboard with your hands, and define a ‘mash hands with keyboard’ method on your class that gets called when the mashing occurs, but it does have something interesting in the implicit operator.

The implicit operator is what C# uses when you try and cast an object to another type. Normally you’d just go (Foo)bar to get yourself a Foo, which is what the stinky explicit operator lets you override. But if you don’t specify the cast, you can just write foo = bar. If the two types don’t match, everything explodes… unless you’ve written yourself an implicit cast operator:

public static implicit operator Foo(Bar bar)
{
    return Foo.FromBar(bar);
}

This is basically overriding the assignment operator, right? Well, unfortunately you can’t override the very important case of assigning a Foo to a Foo, or a Bar to a Bar. But everything else is fine.

Suddenly, it’s really easy to introduce Whole Values into your system. If you’ve been using strings to keep postcodes, you could write something like:

class Postcode
{
    private static readonly Regex _pattern;
    private string _postcode;

    static Postcode()
    {
        _pattern = new Regex(
            "^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][A-Z-[CIKMOV]]{2}$",
            RegexOptions.Compiled);
    }
    private Postcode(string postcode)
    {
        _postcode = postcode;
    }

    public static implicit operator Postcode(string postcodeString)
    {
        return Parse(postcodeString);
    }

    public static implicit operator string(Postcode postcode)
    {
        return postcode == null ? string.Empty : postcode._postcode;
    }

    public static Postcode Parse(string postcodeString)
    {
        Match match = _pattern.Match(postcodeString);
        if (match.Success)
            return new Postcode(match.Value);
        else
            throw new FormatException("Invalid postcode");
    }
}

And now you can say:

Postcode postcode = Console.ReadLine();
string postcodeString = postcode;

Now you have some validation, a named type that better describes what we’re modelling, and we still get to keep using strings when we need them.

But we can add even more into that little ‘=’ operator. Joel spolsky uses turbo mega Hungarian notation to stay safe. Here’s how we can do it in C#:

class SafeString
{
    private bool _safe = false;
    private string _value;

    private SafeString(string value)
    {
        _value = value;
    }

    public static implicit operator SafeString(string value)
    {
        return new SafeString(value);
    }

    public static implicit operator string(SafeString value)
    {
        if (!value.Safe)
            throw new SecurityException("String has not been cleaned");

        return value._value;
    }

    public void Clean()
    {
        // Strip nasty characters!
        _safe = true;
    }

    public bool Safe
    {
        get { return _safe; }
    }
}

Now we can’t get the string back out until we clean it:

private static string ReadUnsafe()
{
    Console.Write("Do Your Worst: ");
    SafeString safe = Console.ReadLine();

    try
    {
        return safe;
    }
    catch (SecurityException)
    {
        Console.WriteLine("Unsafe!");
        return null;
    }
}

That’ll break every time, you don’t have to look at any weird variable prefixes or anything. You just have to do this:

private static string ReadSafe()
{
    Console.Write("Do Your Worst: ");
    SafeString safe = Console.ReadLine();
    safe.Clean();
    string value = safe;
    Console.WriteLine("Safe!");
    return value;
}

I’m not saying this is ground-breaking stuff, and it doesn’t do anything you couldn’t do with methods named FromSomething and ToSomething (which the MSDN article at the top asks you to do anyway). But when you find yourself pumping out ints, strings and such like there’s no tomorrow, remember that you have a simple way to capture that information into something more meaningful. Plus, ‘public static implicit operator’ sounds dead clever, right?

Categories: C# · Code
Tagged: , , ,