août
2012
Bonjour,
Un petit billet rappelant le principe de fonctionnement d’un IEnumerable.
L’IEnumerable offre une interface permettant d’itérer parmi des objets. Dans les faits, cette interface permet de retourner une instance d’IEnumerator (via une méthode GetEnumerator). Cet IEnumerator ne propose que 3 membres :
– Current : propriété permettant de retourner l’élément actuel
– MoveNext() : méthode permettant d’itérer vers l’élément suivant
– Reset() : méthode permettant de réinitialiser l’itérateur
L’utilisation d’un IEnumerable couplé au mot clé yield return permet (entre autre) de streamer au fil de l’eau les objets récupérés depuis une source de données.
Pour info (ou rappel) : le mot clé yield return est un ovni qui remonte un objet à l’appelant (consommateur de IEnumerable), le laissant utiliser l’objet, puis lors de l’appel au Move Next (élément suivant d’un foreach), redescend l’exécution dans la source de données vers le prochain yield return (ou yield break si fin).
Le principal intérêt est (vous l’avez deviné), de pouvoir appliquer un traitement élément par élément, sans jamais devoir monter en mémoire une liste complète d’objets.
Cela améliore l’expérience utilisateur sur des gros chargements de données.
Exemple : Un utilisateur (humain ou machine) doit traiter une grosse quantité d’informations, élément par élément, sans pénaliser l’exploitation des ressources (réseau, matériel, performance).
La source de données peut être un fichier csv, xml, base de données, etc.
Dans ce cas de figure, la mémoire ne contient jamais plus d’un élément !
L’élément suivant n’est chargé que lorsque l’utilisateur le demande (move next dans un foreach).
Le plus important à retenir est que l’exécution du chargement (donc du premier item) n’est réalisé qu’à l’appel du premier move next … comme un IQueryable ! , au contraire d’un ICollection qui pointe vers une implémentation mémoire de liste de données !
Pour illustrer un problème potentiel :
Lors de l’utilisation de WCF Data Services, la récupération d’IEnumerable{T} où T est un type simple n’est pas géré par la couche cliente Service Reference (mais bien par le coté serveur).
Donc, cela nécessite une implémentation « Maison » utilisant une webrequest (côté consommateur de données).
Imaginons une propriété (coté client) qui retourne un IEnumerable{string}, l’appel au serveur ne se fera que lorsque l’itération sur le premier élément aura été sollicitée par le consommateur de la propriété.
A ce moment là, la mécanique yield return sera mise en oeuvre !
Je vous invite également à comparer le code IL (via Reflector, ILSpy, etc) entre l’un implémentation IEnumerable couplé à un yield return avec celle retournant une liste…
Marrant…