2010-10-19 2 views
10

Comme le titre l'indique: Pourquoi string.Join a besoin de prendre un tableau au lieu d'un IEnumerable? Cela continue de m'agacer, puisque je dois ajouter un .ToArray() quand j'ai besoin de créer une chaîne jointe à partir du résultat d'une expression LINQ. Mon expérience me dit qu'il me manque quelque chose d'évident ici.Quelle est la raison string.Join doit prendre un tableau au lieu d'un IEnumerable?

+2

Vous serez heureux de savoir qu'il accepte 'IEnumerable '.NET 4 –

+0

Ma conjecture serait qu'elle a été ajoutée avant IEnumerable. – asawyer

+0

string.Join était ici bien avant Linq. Comment ça vous dérange? Il ne reste plus que quelques caractères à écrire. –

Répondre

9

Mise à niveau vers .NET 4.0 et utilisez le overload qui accepte un IEnumerable<string>. Sinon, il suffit d'accepter que c'était un long problème en suspens qui n'a pas été résolu avant .NET 4.0. Vous pouvez résoudre le problème en créant votre propre méthode d'extension!

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

Utilisation:

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

Jason, merci beaucoup, la programmation est devenue tellement joyeuse! ':)' – sbi

+0

BTW, j'ai effectivement écrit un 'Join (ce IEnumerable chaînes, séparateur de chaînes)' sur cela. Je suis tellement tombé amoureux que, j'ai traversé 100kLoC et adapté toutes les utilisations de 'string.Join()'. – sbi

3

Ce n'est plus le cas. .NET 4 a ajouté some overloads pour le rendre plus facile à utiliser. En particulier, non seulement vous n'avez pas besoin de passer dans un tableau - ce n'est pas non plus une séquence de chaînes. String.Join(String, IEnumerable<T>) appellera ToString sur chaque élément de la séquence.

Si vous n'utilisez pas .NET 4 mais que vous effectuez de nombreuses opérations d'assemblage de chaînes, vous pouvez toujours écrire vos propres méthodes, bien sûr.

+0

Etes-vous en train de me dire qu'il n'y a pas de raison .NET <4 cela? – sbi

+0

@sbi: Yup. C'est juste quelque chose que MS n'aurait vraisemblablement pas réalisé serait aussi utile aux développeurs. Il n'a pas besoin de nouvelles fonctionnalités de .NET 4, autant que je sache. –

+0

Et ici, je m'attendais à un traitement long et éducatif sur les raisons pour lesquelles cela doit être un tableau ... – sbi

8

Overloads of Join that take an IEnumerable<T> argumentOverloads of Join that take an IEnumerable<T> argument ont été introduites dans .NET 4 - si vous n'utilisez pas .NET 4, je crains que vous ne soyez bloqué par le passage d'un tableau ou l'écriture de votre propre implémentation.

Je devine que la raison est simplement que cela n'a pas été jugé assez important quand le cadre a été conçu pour la première fois. IEnumerable<T> est devenu beaucoup plus important avec l'introduction de LINQ.

(Bien sûr, il n'y avait pas de types génériques dans .NET lors de sa conception, mais il n'y a aucune raison pour qu'ils ne l'aient pas fait avec IEnumerable non-générique s'ils l'avaient trouvé utile.)

et il n'y a aucune raison pour laquelle vous ne pouvez pas rouler votre propre version de Join qui prend un IEnumerable<T> si vous sentez que vous avez besoin et vous ne parvenez pas à passer à 4. .NET

+0

... à moins que l'on écrit un * array-to-'IEnumerable ' *, je suppose? C'est ce que les gens de Java ont l'habitude de faire, de toute façon. – Esko

0

Je suppose que String.Join exige la capacité de parcourir le tableau deux fois (une fois pour mesurer la longueur, et une fois à faire la copie). Certaines classes implémentant iEnumerable peuvent être jointes avec succès dans un tableau de chaînes en effectuant une passe pour compter la longueur, en appelant Reset sur l'énumérateur et en utilisant une seconde passe pour copier les données, mais iEnumerable ne prend en charge ni une propriété Capabilities, ni une famille des classes dérivées comme iMultiPassEnumerable, les seules façons pour String.Join d'accepter en toute sécurité un iEnumerable serait soit (1) d'énumérer un type de liste et d'exécuter la jointure dessus, (2) de deviner la taille de la chaîne cible, et de réallouer comme ou (3) combiner les approches, en regroupant les chaînes courtes en groupes de jusqu'à 8K, puis en combinant tous les clusters en un résultat final (qui serait un mélange de clusters pré-concaténés et de longues chaînes du tableau original). Bien que j'assurerais certainement qu'il serait utile pour String.Join d'inclure un overhead qui convertit un iEnumerable en List, je ne vois pas que cela fournirait plus d'efficacité que de faire une telle conversion manuellement (contrairement au version tableau de String.Join, ce qui est plus efficace que de joindre manuellement des chaînes individuellement).

Questions connexes