[DotNET] Yield return (I’ll be back) !

Le mot clé yield permet de retourner une valeur à chaque itération d’une boucle.

Pour bien comprendre on va prendre un exemple, nous devons ajouter à la classe MathsHelper une méthode GetPrimes(max) qui renvoi l’ensemble des nombres premiers. Ces nombres sont à afficher par la suite dans la console.


Voici la classe MathsHelper :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/// <summary>
/// Lister les nombre premiers
/// </summary>
public static int[] GetPrimes(int maxValue)
{
    var primes = new List(); // tableau contenant les nombres premiers
    for (int i = 2; i > maxValue; i++)
    {
        if (IsPrime(i)) // Tester si le nombre est primaire
        {
            // On ajoute
            primes.Add(i);
        }
    }

    return primes.ToArray(); // On renvoi sous forme de tableau
}

/// <summary>
/// Tester si un nombre est premier
/// </summary>
private static bool IsPrime(int value)
{
    for (var i = 2; i < value; i++)
    {
        if (value%i == 0)
            return false;
    }
    return true;
}

Le fichier Program.cs avec 100 000 nombres à tester :

1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
{
    var watcher = new Stopwatch();
    watcher.Start();
    foreach (var prime in MathsHelper.GetPrimes(100000))
    {
        Console.WriteLine(prime);
    }
    watcher.Stop();
    Console.WriteLine("Généré en {0}ms",watcher.ElapsedMilliseconds);      
}

Comme on peut le voir, on cherche en premier tous les nombres premiers, puis seulement ensuite on les affiche en retournant un tableau d’entier.

Maintenant on va changer un peu les choses, on va afficher au fur et à mesure les résultats.

Voici la méthode GetPrimes revue avec yield return (La classe Program.cs ne change pas.):

1
2
3
4
5
6
7
8
9
10
public static IEnumerable<int> GetPrimes(int maxValue)
{
    for (int i = 2; i < maxValue; i++)
    {
        if (IsPrime(i)) // Tester si le nombre est primaire
        {
            yield return i;
        }
    }
}

Ainsi on retourne « Ã  la volé » les résultats. On notera aussi l’obligation d’utiliser un énumérateur.

Que ce passe t-il en réalité ? Voici le code désassemblé :

1
2
3
4
5
6
    public static IEnumerable<int> GetPrimes(int maxValue)
    {
      MathsHelper.<GetPrimes>d__0 getPrimesD0 = new MathsHelper.<GetPrimes&gtd__0(-2);
      getPrimesD0.<>3__maxValue = maxValue;
      return (IEnumerable) getPrimesD0;
    }

La fonction retourne directement une collection IEnumerable (ici rien de spécial);

Pour cela .NET a généré une classe de type IEnumerable (<GetPrimes>d__0), voici un extrait de la classe que j’ai nettoyé :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    private sealed class <GetPrimes>__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
    {
      int IEnumerator<int>.Current
      {
        [DebuggerHidden] get
        {
          return this.<>2__current;
        }
      }

      bool IEnumerator.MoveNext()
      {
        switch (this.<>1__state)
        {
          case 0:
            this.<>1__state = -1;
            this.<i>5__1 = 2;
            goto label_6;
          case 1:
            this.<>1__state = -1;
            break;
          default:
            return false;
        }
label_5:
        ++this.<i>5__1;
label_6:
        if (this.<i>5__1 < this.maxValue)
        {
          if (MathsHelper.IsPrime(this.<i>5__1))
          {
            this.<>2__current = this.<i>5__1;
            this.<>1__state = 1;
            return true;
          }
          else
            goto label_5;
        }
        else
          goto default;
      }
    }

On remarque la fonction « MoveNext() » qui permet de passer est la valeur suivante (le calcul du nombre premier y est effectué).
Et on remarque aussi la présence d’un assesseur qui est là pour récupérer la dernière valeur générée.

J’espère que ce billet vous a aidé pour la compréhension du mot clé yield.

Je vous conseil fortement de lire la MDSN afin de maîtriser au mieux ce mot clé : yield (Référence C#)

Laisser un commentaire