If only you were using .NET 4.0! Oh, wait a minute…

One thing I’ve always found strange is how users on Stack Overflow often say things like, “If you were using .NET Version X, you could do this”—when the feature is more or less trivial to implement yourself.

Take string.Join, for example. Before .NET 4.0, the System.String class had two static Join methods, both of which accepted a string[] parameter. This was a sometimes frustrating limitation of the string type; why do I need an array to join instead of any arbitrary IEnumerable<string>—or even IEnumerable<T>, for that matter?

It’s common to see the following sort of suggestion on SO:

List<string> names = new List<string> { "Homer", "Marge", "Bart", "Lisa", "Maggie" };

// If you're using .NET 4.0:
string joined = string.Join(", ", names);

// If you're using .NET 3.5 or older -- note that pesky ToArray call:
string joined = string.Join(", ", names.ToArray());

Now look, I realize this is pragmatic and totally reasonable. But there’s a reason they introduced new string.Join overloads in .NET 4.0; that reason is that copying a collection to an entirely new array is unnecessarily inefficient. Why should you have to copy your List<string>, LinkedList<string>, Queue<string>, etc. all to string[] arrays before being able to join them? You really shouldn’t. And yet, unless you’re on .NET 4.0, the suggestion is almost always to do precisely that.

If it were really complicated to write your own Join method accepting an IEnumerable<string>, I think I might be more sympathetic to this approach. But I work primarily in .NET 3.5, and it’s always kind of bothered me to have to call ToArray (or even Select(x => x.ToString()).ToArray()) in cases where I’m dealing with an IEnumerable<T>) everywhere I’m creating delimited strings from the contents of non-string[] collections. And the fact is that it’s not complicated at all. So why don’t we encourage people to just do it?

For the record, here’s a very simple version to illustrate what I’m talking about:

public static string Join(string separator, IEnumerable<string> values)
{
    if (values == null)
    {
        throw new ArgumentNullException("values");
    }

    separator = separator ?? "";

    var stringBuilder = new StringBuilder();
    bool pastFirstValue = false;

    foreach (string s in values)
    {
        if (pastFirstValue)
        {
            stringBuilder.Append(separator);
        }

        stringBuilder.Append(s);
        pastFirstValue = true;
    }

    return stringBuilder.ToString();
}

Now, the most obvious objection to this approach would have to be: Why bother? If a method like this is available in .NET 4.0, and you’re going to upgrade to .NET 4.0 at some point, why not just wait until that time and strip out those ToArray calls?

That’s fair, but my response would have to: Why wait? If you’re bothered by having to call ToArray, and an alternative solution is simple to implement yourself… I say just bite the bullet and do it.

What’s more, I recently learned that you can use the C# preprocessor to actually compile different code based on your target framework version. Which means that I can modify the above Join method as follows:

public static string Join(string separator, IEnumerable<string> values)
{
#if NET_FRAMEWORK_4
    // If we're on .NET 4.0, just use the built-in string.Join method.
    return string.Join(separator, values);

#else
    // Otherwise, let's use our own home-grown implementation.
    if (values == null)
    {
        throw new ArgumentNullException("values");
    }

    separator = separator ?? "";

    var stringBuilder = new StringBuilder();
    bool pastFirstValue = false;

    foreach (string s in values)
    {
        if (pastFirstValue)
        {
            stringBuilder.Append(separator);
        }

        stringBuilder.Append(s);
        pastFirstValue = true;
    }

    return stringBuilder.ToString();
#endif
}

This gives us a robust Join implementation which accepts an IEnumerable<string> parameter and will gracefully transition to the built-in string.Join method if and when the target framework version is changed to 4.0. What more could you ask for?

Personally, I’d like to see more of this sort of advice (if the version of the framework you’re using doesn’t include it, write it yourself) and less of the “If only you were on version X” variety out there.

Advertisements

2 thoughts on “If only you were using .NET 4.0! Oh, wait a minute…

  1. Sandeep says:

    Probably a Compiler error at return string.Join(separator, strings); there is no variable called strings but values 🙂

    • Daniel says:

      Yikes! That’s embarrassing… thanks for the correction! (So it’s no secret which framework I compiled against, eh?)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: