Tag Archives: C#

Why won’t my iterator throw?

I ran into a spot of confusion last night doing some TDD on a method that returns an IEnumerable<T>. I was using multiple yield return statements in it which made the method an iterator and not just a normal method.

Even though I know how iterators work, I don’t use them enough to remember their idiosyncrasies. The main one being that it’s easy to “invoke” them without actually executing any of the code inside them!

To illustrate this using a highly contrived example, imagine you wrote the following test:

[Test]
public void It_throws_when_you_pass_in_null()
{
    Assert.Throws<ArgumentNullException>(
        () => MyObject.MyMethod(null));
}

And then implemented the method it tests it like so:

public static IEnumerable<object> MyMethod(object arg)
{
    if (arg == null)
        throw new ArgumentNullException("arg");

    yield return "whatever";
}

Surprise! Your test fails.

Why? Because the code in your iterator doesn’t start executing until you invoke GetEnumerator on its return value then invoke MoveNext on that.

One really quick way to force these method calls to happen is to use the ToArray extension method:

[Test]
public void It_throws_when_you_pass_in_null()
{
    Assert.Throws<ArgumentNullException>(
        () => MyObject.MyMethod(null).ToArray());
}

ToList or manually iterating over the result with foreach would work just as well.

A better way to fix this is to change your implementation so that it uses two methods:

public static IEnumerable<object> MyMethod(object arg)
{
    if (arg == null)
        throw new ArgumentNullException("arg");

    return MyMethodHelper(arg);
}

private static IEnumerable<object> MyMethodHelper(object arg)
{
    yield return "whatever";
}

Written this way, MyMethod isn’t an iterator anymore. It’s just a plain old method that gets executed the way you’d expect it to. MyMethodHelper becomes the iterator. Its code won’t get executed until you start calling MoveNext, but that’s OK because the validation code you care about already ran.

Problem solved, right? Unfortunately, this wasn’t quite my exact problem.

My method was actually throwing after it did its argument checking and while it was yielding values. There’s really no solution (that I know of) to handle this without invoking MoveNext (or something else that will invoke it for you like ToArray) until whatever condition throws your exception is triggered.

Adding ToArray to my test wasn’t a big deal, but it took me a bit of time to figure out why it was failing. I was actually setting breakpoints in my method, running the test in the debugger, and tripping out when my breakpoints weren’t hitting.

Maybe going through the trouble of writing this post will save me 10 minutes next time I write an iterator.

RogueSharp

I just pushed a pet project of mine up to GitHub today. It’s a port of the original game of Rogue from C to C#. It’s not complete–it doesn’t save your progress and let you continue on later, but it is playable.

Now that the actual port is done, I plan on cleaning up the code. Like most software written in C in the 80s, it relies on way too many global variables, uses an abundance of switch statements on object types, and has no abstraction between the game logic and the UI. Since it’s on GitHub, that should leave a nice history of the refactorings I try to apply to it. Of course, before I can try to do any refactoring, I need to get some tests in place. That should be fun considering how much it relies on direct access to the curses library and a random number generator.

The repository is here. Feel free to fork it to help out if you like.

Splitting CamelCase With Regular Expressions

On my new project, I needed to split a method name up into its constituent parts.

For Ruby programmers, this is easy: just split on underscores. For us .NET programmers, we need something a little fancier since we like to SquashOurMethodNamesTogetherLikeThis.

Here’s a little regular expression that can do exactly that:

(?<!^)(?=[A-Z])

That basically says to match right before every capital letter unless the capital letter is at the beginning of the string.

You can use the Regex.Split method to do the actual work of turning the method name into a string array:

Regex splitter = new Regex(@"(?<!^)(?=[A-Z])");
string[] words = splitter.Split(methodName);

My friend, Michael Kennedy, demoed in class recently how to use LINQPad to test regular expressions. It came in really handy while working on this:

linqpad-with-regex

I really need to click that “Activate Autocompletion” button so I can give Joseph Albahari the money he deserves for creating such a useful tool.

By the way, I used to think that “camel case” was for words like “camelCase” and “pascal case” was for words like “PascalCase”, but Wikipedia doesn’t make that distinction.

My UnWordify Extension Method

Tim Barcz is looking for a solution to an interesting problem in his Coding Contest: Create a Programming Pearl post.

I decided to challenge myself by writing my solution as a single “line” of code:

public static class StringExtensions
{
    private static Dictionary<char, char> _charMap = new Dictionary<char, char>
    {
        { (char)8208,  (char)45 },
        { (char)8211,  (char)45 },
        { (char)8212,  (char)45 },
        { (char)8722,  (char)45 },
        { (char)173,   (char)45 },
        { (char)8209,  (char)45 },
        { (char)8259,  (char)45 },
        { (char)96,    (char)39 },
        { (char)8216,  (char)39 },
        { (char)8217,  (char)39 },
        { (char)8242,  (char)39 },
        { (char)769,   (char)39 },
        { (char)768,   (char)39 },
        { (char)8220,  (char)34 },
        { (char)8221,  (char)34 },
        { (char)8243,  (char)34 },
        { (char)12291, (char)34 },
        { (char)160,   (char)32 },
        { (char)8195,  (char)32 },
        { (char)8194,  (char)32 }
    };

    public static string UnWordify(this string value)
    {
        return new string((from c in value
                           select _charMap.ContainsKey(c) ? _charMap[c] : c)
                          .ToArray());
    }
}

OK, so I cheated and used a dictionary to create my map from the bad characters to the good ones, but the actual method is a single statement.