Aujourd’hui pour bien commencer la semaine, on va aborder deux opérateurs que j’affectionne tout particulièrement : Single et SingleOrDefault.

Pour ces opérateurs, on va devoir préciser notre classe MembreDeveloppez en y ajoutant un champ ID qui représente un identifiant unique pour chaque membre de developpez.com.

public class MembreDeveloppez : IComparable<MembreDeveloppez>
{
        public int ID { get; set; }
        public string Nom { get; set; }
        public int NombreMessages { get; set; }
        // …
}

Et au passage, voici la nouvelle implémentation de la méthode GetMembresDeveloppez() qui (pour ceux qui n’auraient pas suivi) retourne une liste d’instances de la classe MembreDeveloppez :

public static List<MembreDeveloppez> GetMembresDeveloppez()
{
        return new List<MembreDeveloppez>() 
        { 
                new MembreDeveloppez(){ ID=1, Nom=« Jérôme Lambert », NombreMessages = 3000},
                new MembreDeveloppez(){ ID=2, Nom=« Louis-Guillaume Morand », NombreMessages = 2500},
                new MembreDeveloppez(){ ID=3, Nom=« Aspic », NombreMessages = 1200},
                new MembreDeveloppez(){ ID=4, Nom=« Dev01″, NombreMessages = 530},
                new MembreDeveloppez(){ ID=5, Nom=« Giovanny Temgoua », NombreMessages = 8300},
                new MembreDeveloppez(){ ID=6, Nom=« LefortLudovic », NombreMessages = 1200},
                new MembreDeveloppez(){ ID=7, Nom=« nico-pyright(c) », NombreMessages = 660},
                new MembreDeveloppez(){ ID=8, Nom=« Skyounet », NombreMessages = 4300},
                new MembreDeveloppez(){ ID=9, Nom=« Smyley », NombreMessages = 2200}
                // …
        };
}

Maintenant la question du jour : comment feriez-vous pour récupérer un membre de developpez.com sur base de son identifiant ? On va prendre comme exemple le membre Skyounet avec l’identifiant 8.

J’ai l’impression que certains, qui ont suivi cette série de billets depuis le début, ont envie de proposer une solution avec l’opérateur First (voir FirstOrDefault) :

var membres = SampleLibrary.MembreDeveloppez.GetMembresDeveloppez();
SampleLibrary.MembreDeveloppez membreID8 = membres.First(membre => membre.ID == 8);

Et bien pas de chance mais ce n’est pas tout à fait juste car on parle bien d’identifiant unique. Or avec l’opérateur First (ou FirstOrDefault), on récupère que le premier élément de la séquence résultante, or, si notre séquence venait à contenir plus d’un membre avec l’identifiant 8, il y aurait un réel problème au niveau de l’intégrité de vos données et pire encore, vous auriez fermé les yeux face à ce cas.

Le code suivant va donc s’exécuter correctement mais vous passerez à côté du fait que deux membres ont l’identifiant 8 :

var membres = SampleLibrary.MembreDeveloppez.GetMembresDeveloppez();
membres.Add(new SampleLibrary.MembreDeveloppez() { ID = 8, Nom = « Inconnu numéro 8″, NombreMessages = 0 });
SampleLibrary.MembreDeveloppez membreID8 = membres.First(membre => membre.ID == 8);

C’est là que notre opérateur Single va être intéressant car il renverra une exception dans deux cas :

  1. Lorsqu’il n’y aura pas d’élément dans notre résultat (comme avec First d’ailleurs)
  2. Lorsqu’il y aura plus d’un élément dans notre résultat !

Le second cas répond donc exactement à notre problématique :

var membres = SampleLibrary.MembreDeveloppez.GetMembresDeveloppez();
membres.Add(new SampleLibrary.MembreDeveloppez() { ID = 8, Nom = « Inconnu numéro 8″, NombreMessages = 0 });
try
{
        SampleLibrary.MembreDeveloppez membreID7 = membres.Single(membre => membre.ID == 7);
        //SampleLibrary.MembreDeveloppez membreID8 = membres.Single(membre => membre.ID == 8); // => Génère une exception
        Console.WriteLine(« Le membre avec l’identifiant 8 est {0} », membreID7.Nom);
}
catch (System.Exception exc)
{
        Console.WriteLine(« La requête n’a pas renvoyé un et un seul membre. »);
}

Pour ce qui est de l’opérateur SingleOrDefault, il se comporte comme Single excepté le fait qu’il renverra null lorsque le résultat n’aura pas d’élément (contrairement à Single qui génèrera une exception).

try
{
        SampleLibrary.MembreDeveloppez membreID1000 = membres.SingleOrDefault(membre => membre.ID == 1000);
        if (membreID1000 != null)
        {
                Console.WriteLine(« Le membre avec l’identifiant 1000 est {0} », membreID1000.Nom);
        }
        else
        {
                Console.WriteLine(« Il n’existe pas de membre avec l’identifiant 1000. »);
        }
}
catch (System.Exception exc)
{
        Console.WriteLine(« La requête n’a pas renvoyé un et un seul membre. »);
}

Alors fan ou pas ?!