L'approche générale▲
Le but est de réimplémenter Linq To Objects tout entier, en expliquant chaque méthode (ou groupe de méthodes) dans un billet de blog. Je vais essayer de créer un code de qualité pour la production mais je ne vais inclure aucune documentation XML (pour ne pas faire doublon avec les explications du billet traitant le sujet). J'inclurai des optimisations le cas échéant, espérant faire mieux que Linq To Objects lui-même.
L'approche va être assez simple : pour chaque méthode LINQ, j'écrirai quelques tests unitaires (je ne montrerai pas la plupart dans les billets du blog) et m'assurerai qu'ils s'exécutent contre l'implémentation normale de Linq To Objects. Je commenterai ensuite la directive using System.Linq et introduirai à la place la directive using JonSkeet.Linq. Les tests échoueront, j'implémenterai les méthodes et peu à peu ils passeront au vert. Ce n'est pas tout à fait le pattern TDD mais ça fonctionne très bien.
J'écrirai un billet pour chaque opérateur LINQ, incluant probablement tout le code de production mais seulement les tests « intéressants ». Je vais mettre en évidence les patterns importants au fur et à mesure - c'est aussi le but de l'exercice bien sûr.
À la fin de chaque billet, j'inclurai un lien pour télécharger le « code correspondant ». Par souci pour ceux qui rechercheront ces billets dans le futur, je vais numéroter séparément les téléchargements plutôt qu'un seul téléchargement au fil du temps. J'espère que le code grossira tout simplement, mais j'ose dire qu'il y aura aussi des modifications en cours de route.
L'objectif est de ne pas se retrouver avec LINQBridge : je vais cibler .NET 3.5 (la plupart du temps, pour que je puisse utiliser les méthodes d'extensions sans pour autant créer mon propre attribut) et je ne vais certainement pas commencer à me soucier des installateurs et assimilés. Le but de tout cela est purement pédagogique : si vous suivez ces billets de blog, avec un peu de chance vous aurez une compréhension plus profonde de LINQ en général et LINQ to Objects en particulier. Par exemple, des sujets telle que l'exécution différée sont souvent mal compris : en regardant l'implémentation cela peut assez bien clarifier les choses.
Test▲
Les tests unitaires seront créés en utilisant NUnit (juste parce que c'est ce que je connais le mieux). De manière assez évidente, une des choses que nous aurons besoin de tester assez souvent sera de savoir si deux séquences sont égales. Nous allons faire cela en utilisant la classe TestExtensions de MoreLinq (que je viens de copier dans le projet). Le notebook sur lequel je vais probablement écrire la plupart du code a seulement C# Express 2010 d'installé, donc je vais utiliser l'interface utilisateur externe de NUnit. J'ai configuré cela dans le fichier de projet comme étant le programme à démarrer… ce que vous ne pouvez pas faire directement à partir de C# Express, mais vous pouvez facilement éditer le fichier de projet pour y inclure ceci :
<StartAction>
Program</StartAction>
<StartProgram>
C:\Program Files\NUnit-2.5.7.10213\bin\net-2.0\nunit-x86.exe</StartProgram>
C'est un hack un peu minable mais il fonctionne. Les « autres paramètres de ligne de commande » sont ensuite définis dans JonSkeet.Linq.Tests.dll - le répertoire courant est le répertoire bin/debug par défaut, donc tout va bien. Évidemment, si vous voulez exécuter les tests vous-même et si vous avez ReSharper ou quelque chose de semblable, vous pouvez voir les résultats intégrés dans Visual Studio.
Bien que j'espère écrire un code de niveau adéquat pour la production, je doute qu'il y aura autant de tests unitaires que j'en écrirais vraiment pour du code de production. Je m'attends aussi à ce que le nombre de lignes de code de test éclipse le nombre de lignes de code de production. Il y a juste un nombre immense de cas aux limites potentiels… pour un certain nombre de surcharges dans plusieurs cas. Rappelez-vous que le but ici est d'examiner les aspects intéressants de LINQ.
Mise en forme du code▲
Tout comme le vrai Linq To Objects, je vais être amené à créer une énorme classe statique Enumerable… mais je vais le faire en utilisant des classes partielles, avec une seule méthode (mais de multiples surchriptarges) par fichier. Alors Where sera implémenté dans Where.cs et testé dans WhereTest.cs par exemple.
Livraison du premier code▲
Le premier fichier zip est disponible : Linq-To-Objects-1.zip. Il ne contient encore aucun code de production - juste quatre tests pour le Where, pour que je puisse vérifier que NUnit fonctionne correctement pour moi. Prochain arrêt… implémentation du Where.
Remerciements▲
Je tiens ici à remercier Jon Skeet de m'avoir autorisé à traduire son article Reimplementing LINQ to Objects: Part 1 - Introduction.
Je remercie Tomlev pour sa relecture technique et ses propositions.
Je remercie également F-leb pour sa relecture orthographique et ses propositions.