Welcome to MSDN Blogs Sign in | Join | Help

News


  • Locations of visitors to this page
Sondage: string ou collection ?

Tous les jours, nos programmes utilisent de nombreuses variables de tout type. Parmi elles, les chaines de caractères y sont massivement présentes. Ce besoin évident de stocker du texte cause cependant de nombreux problèmes depuis toujours.

En effet, on attend d'une chaine de caractère de pouvoir lui concaténer une autre chaine, de la réduire en supprimant certains caractères, de la passer en majuscule, etc.

Toutes ces opérations changent la taille mémoire de la chaine et posent problème car on s'aperçoit bel et bien que l'on a à faire à un tableau (ou buffer) et non pas à un type simple.

Le framework .Net a donc pris le choix de considérer le type string comme immuable. Qu'est-ce donc ?

Celà veut dire qu'une fois une chaine allouée, on ne peut plus la modifier. Toute opération créera donc une autre chaine de caractères.

Nous savons qu'il n'est pas recommandé de concaténer plusieurs chaines de caractère de suite. En effet l'opération suivante, bien que d'apparence banale est très consommatrice en mémoire.

string s = "Bonjour Mr " + nom + " " + prenom + ".";

Chaque concaténation va créer et allouer autant de fois que nécessaire de nouvelles chaines de caractère alors que notre finalité est d'en créer une seule.
La classe StringBuilder ou encore la méthode string.Format() sont alors beaucoup plus efficaces.

Ce rappel sur les chaines est toujours intéressant mais ce n'est qu'une introduction. C# 3.0 et la technologie Linq se basent fortement sur les énumérations. Les tableaux .Net sont des énumérations typées. Ainsi, la classe string, comme tout tableau, implémente IEnumerable<Char>.

On peut trouver beaucoup d'avantages à voir une chaine comme étant une énumération.

Par exemple, s.Skip(10).Take(5).Skip(10) n'alloue aucune chaine intermédiaire contrairement à: s.Substring(10, 5) + s.Substring(10 + 5 + 10,  s.Length - (10+5+10)).

Donc tant que l'on appelle des méthodes Linq en séquence, on ne fait que jouer avec des énumérations sans créer de collection intermédiaire. (cf Pourquoi préférer les itérations aux collections)

L'avantage est considérable mais un problème subsiste: le résultat n'est pas une chaine mais IEnumerable<Char>. Comment revenir à une simple chaine ?

Revenir d'une énumération de caractères à une chaine les concaténant tous revient finalement à faire une aggrégation sur la série comme on le ferait en calculant la somme d'une liste d'entiers.

Ainsi il est possible d'appeler:

string result = "";
s.Skip(10).Aggregate(result, (r, c) => r = r + c);

Attention car nous retombons sur le problème initial de concaténation de chaine. Nous pouvons le résoudre avec la même solution:

StringBuilder result = new StringBuilder();
s.Skip(10).Aggregate(result, (r, c) => r.Append(c));

Voici un petit exemple mettant en oeuvre cette technique. L'idée est d'implémenter une méthode renvoyant la liste des mots contenus dans une chaine de caractères.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace TestConstructorParameter { public static class MyStringExtentions { public static IEnumerable<string> ToWords(this IEnumerable<char> source) { StringBuilder wordBuilder = new StringBuilder(); foreach (char c in source) { if (c != ' ') wordBuilder.Append(c); else { if (wordBuilder.Length > 0) { yield return wordBuilder.ToString(); wordBuilder = new StringBuilder(); } } } if (wordBuilder.Length > 0) yield return wordBuilder.ToString(); } } public class Program { static void Main(string[] args) { string source = "Bonjour tout le monde"; foreach (string s in source.ToWords()) Console.WriteLine(s); } }

Allez pour finir, un petit sondage. L'intellisense des méthodes d'extension de Linq a été retiré de Visual Studio 2008 Beta 2. Lors des précédentes versions, l'équipe C# a reçu beaucoup de retours de développeurs trouvant troublant de considérer les chaines de caractères comme des énumérations de char et de voir ainsi les méthodes de Linq cotoyer les méthodes classiques substring, split et autres.
...depuis, ils ont des retours demandant pourquoi diable l'intellisense avait-elle disparu :-).

A vous de voter en répondant à ce post !

Mitsu

Posted: Wednesday, September 26, 2007 10:11 PM by mitsu
Filed under: , ,

Comments

Danuz said:

Merci pour ce billet que je trouve très intéressant :-). ( Je me suis dis la même chose pour l'intelliense des méthodes d'extension :D! )

# September 27, 2007 3:39 AM

Florian said:

J'essaie justement d'optimiser un parser texte. Je suis entrain de faire des tests avec Linq (plus pour le fun pour le moment). Merci pour l'article !

# September 28, 2007 10:21 AM

mitsu said:

Merci pour les commentaires, mais n'oubliez pas le sondage !!

Alors, intellisense sur les méthodes d'extension sur la classe string dans VS2008 RTM ou pas ???

# September 30, 2007 5:14 PM

Matthieu MEZIL said:

Pour l'intellisence.

Je trouve assez surprenant de pouvoir faire quelque chose et que l'intellisence ne nous le propose pas.

Cependant si des personnes sont contre, on peut éventuellement proposer une solution intermédiaire en ne faisant proposé à l'intellisence que le AsEnumerable().

Mais bon, personnellement, je préfère vraiment avoir tout.

# October 1, 2007 5:13 AM

ericmitt said:

Je suis pour ! une chaine n'est rien d'autre qu'une collection de char...autant le voir dans l'intellisense :-) d'autant que cela compile !

# October 1, 2007 10:00 AM

Tetranos said:

Plutôt d'accord avec les avis précédents. Qui peut le plus peut le moins, je ne vois donc pas pourquoi il faudrait "masquer" certaines méthodes dans l'intellisense.

# October 2, 2007 2:55 AM

Flavien said:

A mon avis, il serait plus logique de le proposer dans l'intellisense, par contre une option pour désactiver les extensions methods de l'intellisense pourrait mettre tout le monde d'accord !

# October 2, 2007 5:59 AM

Miiitch said:

Peut-être qu'il faut des standart/advanced pour l'intellisence. Il y a déjà des trucs comme cela: la configuration "Just My Code" est très pratique pour simplifier la call-stack. Même si des fois, il nous faut voir toute la stack.

# October 2, 2007 9:56 AM

romagny13 said:

Plutot pour

(l'intelliSense etant la pour aider et eviter de tout retenir "par coeur")

peut etre en differenciant les methodes d'extensions des autres methodes avec un icone particulier par exemple ..

# October 4, 2007 2:51 PM

finizi said:

définitivement Pour !

Mais ne pourrait-on pas avoir une petite marque distinctive précisant la catégorie à laquelle appartient la méthode ?

# October 24, 2007 6:34 PM

lea said:

string :)

www.lingerie-emotion.com

# November 29, 2007 8:39 AM

Mitsuru FURUTA - Microsoft FRANCE said:

Réponse au quizz précédent. Ce quizz va me permettre de rappeler plusieurs points intéressants: - Jouer

# August 18, 2008 5:44 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker