简体   繁体   中英

What is the reason string.Join needs to take an array instead of an IEnumerable?

As the title says: Why does string.Join need to take an array instead of an IEnumerable? This keeps annoying me, since I have to add a .ToArray() when I need to create a joined string from the result of a LINQ expression.

My experience tells me that I'm missing something obvious here.

Upgrade to .NET 4.0 and use the overload that accepts an IEnumerable<string> . Otherwise, just accept that it was a long outstanding problem that wasn't addressed until .NET 4.0. You can fix the problem by creating your own extension method too!

public static class StringEnumerableExtensions {
    public static string Join(this IEnumerable<string> strings, string separator) {
        return String.Join(separator, strings.ToArray());
    }
}

Usage:

IEnumerable<string> strings;
Console.WriteLine(strings.Join(", "));

Overloads of Join that take an IEnumerable<T> argument were introduced in .NET 4 - if you're not using .NET 4 then I'm afraid you're stuck with passing an array or writing your own implementation.

I'm guessing that the reason is simply that it wasn't deemed important enough when the framework was first being designed. IEnumerable<T> became a lot more prominent with the introduction of LINQ.

(Of course, there were no generic types in .NET when it was being designed, but there's no reason why they couldn't have done it with plain non-generic IEnumerable if they'd have thought it worthwhile.)

And there's no reason why you can't roll your own version of Join that takes an IEnumerable<T> if you feel that you need it and you're unable to upgrade to .NET 4.

It doesn't, any more. .NET 4 added some overloads to make this easier to use. In particular, not only do you not need to pass in an array - it doesn't need to be a string sequence either. String.Join(String, IEnumerable<T>) will call ToString on each item in the sequence.

If you're not using .NET 4 but are performing a lot of string-joining operations, you could always write your own methods, of course.

I would guess that String.Join requires the ability to iterate through the array twice (once to measure length, and once to do the copy). Some classes which implement iEnumerable could be successfully joined into a string array by doing one pass to count the length, calling Reset on the enumerator, and using a second pass to copy the data, but since iEnumerable supports neither a Capabilities property, nor a family of derived classes like iMultiPassEnumerable, the only ways String.Join could safely accept an iEnumerable would be to either (1) enumerate to some type of list and run the join on that, (2) guess at the target string size, and reallocate as needed, or (3) combine the approaches, grouping short strings into clusters of up to eg 8K, and then combining all clusters into a final result (which would be a mixture of pre-concatenated clusters and long strings from the original array).

While I would certainly grant that it would be handy for String.Join to include an overhead that converts an iEnumerable to a List, I don't see that it would provide any more efficiency than doing such conversion manually (unlike the array version of String.Join, which is more efficient than manually joining strings individually).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM