В чем причина string.Join нужно взять массив вместо IEnumerable?
Как говорится в заголовке: Почему string.Join
нужно взять массив вместо IEnumerable? Это меня раздражает, так как я должен добавить .ToArray(), когда мне нужно создать объединенную строку из результата выражения LINQ.
Мой опыт говорит мне, что я пропустил что-то очевидное здесь.
Ответы
Ответ 1
Перейдите на .NET 4.0 и используйте перегрузку, которая принимает IEnumerable<string>
. В противном случае просто примите, что это была давняя проблема, которая не была решена до .NET 4.0. Вы можете устранить проблему, создав свой собственный метод расширения!
public static class StringEnumerableExtensions {
public static string Join(this IEnumerable<string> strings, string separator) {
return String.Join(separator, strings.ToArray());
}
}
Использование:
IEnumerable<string> strings;
Console.WriteLine(strings.Join(", "));
Ответ 2
В .NET 4 были введены перегрузки Join
, которые принимают аргумент IEnumerable<T>
- если вы не используете .NET 4 то я боюсь, что вы застряли в передаче массива или создании собственной реализации.
Я предполагаю, что причина в том, что он не считался достаточно важным, когда структура была впервые разработана. IEnumerable<T>
стал намного более заметным с введением LINQ.
(Конечно, не было никаких общих типов в .NET при его разработке, но нет причин, по которым они не могли бы сделать это с обычным не-общим IEnumerable
, если бы они сочли это целесообразным. )
И нет причин, по которым вы не можете перевернуть свою собственную версию Join
, которая принимает IEnumerable<T>
, если вы считаете, что она вам нужна, и вы не можете перейти на .NET 4.
Ответ 3
Это не так..NET 4 добавил некоторые перегрузки, чтобы сделать это проще в использовании. В частности, вам не только не нужно проходить в массиве, но и не обязательно иметь последовательность строк. String.Join(String, IEnumerable<T>)
будет вызывать ToString
для каждого элемента последовательности.
Если вы не используете .NET 4, но выполняете много операций по объединению строк, вы всегда можете написать свои собственные методы, конечно.
Ответ 4
Я бы предположил, что String.Join требует возможности повторного итерации массива дважды (один раз для измерения длины и один раз для копирования). Некоторые классы, которые реализуют iEnumerable, могут быть успешно объединены в строковый массив, выполнив один проход для подсчета длины, вызвав Reset в перечислителе и используя второй проход для копирования данных, но так как iEnumerable не поддерживает ни свойство Capabilities, ни семейство производных классов, таких как iMultiPassEnumerable, единственные способы, с помощью которых String.Join может смело принять iEnumerable, будет либо (1) перечислять в некоторый тип списка, либо запустить соединение на нем, (2) угадать размер целевой строки и перераспределять по мере необходимости или (3) комбинировать подходы, группируя короткие строки в кластеры до, например, 8K, а затем объединение всех кластеров в конечный результат (который будет представлять собой смесь предварительно конкатенированных кластеров и длинных строк из исходного массива).
В то время как я, конечно же, буду признателен, что String.Join будет содержать накладные расходы, которые преобразуют iEnumerable в список, я не вижу, чтобы он обеспечивал большую эффективность, чем такое преобразование вручную (в отличие от массива версия String.Join, которая более эффективна, чем ручное объединение строк отдельно).