A Little C# Extension Gem

Over the years, I’ve written this loop in countless languages, countless times:

bool first = true;
foreach (var value in collection) {
    if (!first)
       WriteToOutput(", ");
    first = false;
    WriteToOutput(value.ToString());
}

Or something similar. It’s easy enough to write, but for the sake of DRY (Don’t Repeat Yourself), I decided to finally put this one to bed by writing a C# extension method.

public static IEnumerable<T> Interleave<T>(this IEnumerable<T> contents,
            T separator, bool includeSeparatorFirst = false) {
    bool first = true;
    foreach (T t in contents) {
        if (!first || includeSeparatorFirst)
            yield return separator;
        first = false;
        yield return t;
    }
}

The previous chunk of code would change to:

foreach (string s in collection.Select(value => value.ToString()).Interleave(", "))
    WriteToOuput(s);

If you’ve ever written code to write code, this is a very good thing, but it could be even better. Let’s build an add-on that’s better tuned for code:

public static IEnumerable<T> BracketInterleave<T>(this IEnumerable<T> contents,
            T start, T end, T separator, bool includeSeparatorFirst = false) {
    yield return start;
    foreach (T t in contents.Interleave(separator, includeSeparatorFirst))
        yield return t;
    yield return end;
}

Suppose you have an array of bytes that you want to write out as a declaration. You can do that with the following:

public void WriteArrayDecl(string visibility, string name, byte[] data) {
    WriteToOuput($"{visibility} byte[] {name} =");
    foreach (string s in data.Select(b => String.Format("0x{X2)", b)).BracketInterleave("{\n    ", "}\n", ", "))
        WriteToOuputWithWrapping(s);
}

So we can see that with a little work, we can add an extension method that will make it easier to avoid repeating that old pattern when you need to do common tasks, like writing CSV files, writing code output, or any other similar task.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.