80 votes

Quel est le but / avantage de l'utilisation d'itérateurs de retour sur rendement en C #?

Tous les exemples que j'ai vus de l'utilisation de yield return x; dans une méthode C # pourraient être réalisés de la même manière en renvoyant simplement la liste entière. Dans ces cas, l'utilisation de la syntaxe yield return présente-t-elle un avantage ou un avantage par rapport au renvoi de la liste?

De plus, dans quels types de scénarios yield return seraient utilisés et vous ne pourriez pas simplement renvoyer la liste complète?

121voto

Mehrdad Afshari Points 204872

Mais que faire si vous avez été la construction d'une collection de vous-même?

En général, les itérateurs peuvent être utilisés pour paresseusement générer une séquence d'objets. Par exemple Enumerable.Range méthode ne permet pas d'avoir tout type de collection en interne. Il génère simplement le numéro suivant sur la demande. Il existe de nombreuses utilisations de ce paresseux génération de séquences à l'aide d'une machine d'état. La plupart d'entre eux sont couverts par les concepts de la programmation fonctionnelle.

À mon avis, si vous êtes à la recherche à des itérateurs tout comme un moyen de les énumérer, au travers d'une collection (c'est juste un de la plus simple des cas d'utilisation), vous allez dans le mauvais sens. Comme je l'ai dit, les itérateurs sont des moyens pour retourner les séquences. La séquence peut être même infini. Il n'y aurait pas moyen de revenir une liste avec une longueur infinie et d'utiliser le premier 100 articles. Il a d'être paresseux parfois. De retour d'une collection est considérablement différent de retourner une collection de générateur (qui est ce que l'itérateur est). C'est comparer des pommes à des oranges.

Exemple hypothétique:

static IEnumerable<int> GetPrimeNumbers() {
   for (int num = 2; ; ++num) 
       if (IsPrime(num))
           yield return num;
}

static void Main() { 
   foreach (var i in GetPrimeNumbers()) 
       if (i < 10000)
           Console.WriteLine(i);
       else
           break;
}

Cet exemple tirages de nombres premiers inférieurs à 10000. Vous pouvez facilement le modifier pour imprimer les numéros de moins de un million de sans toucher le premier algorithme de génération de nombres. Dans cet exemple, vous ne pouvez pas retourner une liste de tous les nombres premiers, car la séquence est infini et le consommateur ne sait même pas combien d'articles il veut depuis le début.

24voto

Ray Points 1234

L'amende réponses ici suggèrent qu'une prestation de yield return , c'est que vous n'avez pas besoin de créer une liste, Listes peuvent être coûteux. (Aussi, après un certain temps, vous trouverez encombrants et peu élégante.)

Mais que faire si vous n'avez pas une Liste?

yield return vous permet de traverser les structures de données (pas nécessairement des Listes) dans un certain nombre de façons. Par exemple, si votre objet est un Arbre, vous pouvez parcourir les nœuds en pré - ou post - ordre sans créer d'autres listes ou de la modification de la structure de données sous-jacente.

public IEnumerable<T> InOrder()
{
    foreach (T k in kids)
        foreach (T n in k.InOrder())
            yield return n;
    yield return (T) this;
}

public IEnumerable<T> PreOrder()
{
    yield return (T) this;
    foreach (T k in kids)
        foreach (T n in k.PreOrder())
            yield return n;
}

17voto

Joel Coehoorn Points 190579

Évaluation Différée/Exécution Différée

Le "taux de retour" itérateur blocs ne s'exécute tout le code jusqu'à ce que vous fait appel pour que des résultats précis. Cela signifie qu'ils peuvent aussi être liés ensemble de manière efficace. Pop quiz: en supposant que le "ReadLines()" fonction lit toutes les lignes d'un fichier texte et est mis en œuvre à l'aide d'un itérateur bloc, combien de fois le code suivant itérer sur le fichier?

var query = ReadLines(@"C:\MyFile.txt")
                            .Where(l => l.Contains("search text") )
                            .Select(l => int.Parse(l.SubStrin(5,8))
                            .Where(i => i > 10 );

int sum=0;
foreach (int value in query) 
{
    sum += value;
}

La réponse est exactement un, et que pas jusqu'en bas dans l' foreach boucle.

La séparation des Préoccupations

De nouveau à l'aide de l'hypothétique ReadLines() fonction à partir de ci-dessus, nous pouvons maintenant facilement séparer le code qui lit le fichier à partir du code qui filtre de l'onu-les lignes de code qui fait l'analyse des résultats. Le fait que la première, en particulier, est très ré-utilisable.

Infini Listes

Voir ma réponse à cette question pour un bon exemple:
http://stackoverflow.com/questions/1076001/need-help-with-c-fibonacci

Fondamentalement, je mets en œuvre la séquence de fibonacci à l'aide d'un itérateur bloc qui ne sera jamais s'arrêter (du moins, pas avant d'atteindre l'exemple maxint), et ensuite utiliser que la mise en œuvre de façon sécuritaire.

12voto

SPIRiT_1984 Points 766

Parfois, les séquences de retour sont tout simplement trop grand pour tenir dans la mémoire. Par exemple, environ 3 mois, j'ai pris part à un projet de migration de données entre les états membres SLQ bases de données. Des données ont été exportées au format XML. Taux de retour s'est avéré être très utile avec les XmlReader. Il fait de la programmation beaucoup plus facile. Par exemple, supposons qu'un fichier a 1000 Clientèle éléments - si vous venez de lire ce fichier dans la mémoire, il faudra donc pour enregistrer tous les fichiers dans la mémoire en même temps, même s'ils sont traités de manière séquentielle. Ainsi, vous pouvez utiliser des itérateurs pour parcourir la collection un par un. Dans ce cas, vous avez passer de la mémoire pour un élément.

Comme il s'est avéré, à l'aide de XmlReader pour notre projet était la seule façon de faire la demande de travail - il a travaillé pendant une longue période, mais au moins il n'a pas bloquer l'ensemble du système et n'a pas soulevé OutOfMemoryException. Bien sûr, vous pouvez travailler avec XmlReader sans rendement des itérateurs. Mais les itérateurs rendu ma vie beaucoup plus facile (je ne voudrais pas écrire le code pour importer rapidement et sans problèmes). Regardez cette page afin de voir, comment le rendement des itérateurs sont utilisés pour résoudre des problèmes réels (et pas seulement scientifique avec un nombre infini de séquences).

9voto

Dans les scénarios de jouets / démonstrations, il n'y a pas beaucoup de différence. Mais il existe des situations dans lesquelles il est utile de générer des itérateurs. Parfois, la liste complète n’est pas disponible (par exemple, les flux), ou la liste est coûteuse en ressources informatiques et ne sera probablement pas nécessaire dans son intégralité.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X