2008-08-19 8 views
12

Je sais ce que fait yield, et j'ai vu quelques exemples, mais je ne peux pas penser à des applications réelles, l'avez-vous utilisé pour résoudre un problème spécifique?Quelles sont les applications réelles du rendement?

(idéalement un problème qui ne peut pas être résolu d'une autre manière)

Répondre

8

Je me rends compte que c'est une vieille question (avant Jon Skeet?) Mais j'ai considéré cette question moi-même juste récemment. Malheureusement, les réponses actuelles (à mon avis) ne mentionnent pas l'avantage le plus évident de la déclaration de rendement. Le plus grand avantage de l'instruction yield est qu'elle vous permet d'effectuer des itérations sur de très grandes listes avec une utilisation de la mémoire beaucoup plus efficace, en utilisant par exemple une liste standard. Par exemple, supposons que vous ayez une requête de base de données qui renvoie 1 million de lignes. Par exemple, disons que vous avez une requête de base de données qui renvoie 1 million de lignes. Vous pouvez récupérer toutes les lignes à l'aide d'un DataReader et les stocker dans une liste, ce qui nécessite par conséquent list_size * row_size octets de mémoire. Vous pouvez également utiliser l'instruction yield pour créer un Iterator et stocker uniquement une seule ligne en mémoire à la fois. En effet, cela vous donne la possibilité de fournir une capacité de "streaming" sur de grands ensembles de données.

De plus, dans le code qui utilise l'Iterator, vous utilisez une simple boucle foreach et pouvez décider de sortir de la boucle si nécessaire.Si vous vous cassez tôt, vous n'avez pas forcé la récupération de l'ensemble des données lorsque vous avez seulement besoin des 5 premières lignes (par exemple).

En ce qui concerne:

Ideally some problem that cannot be solved some other way 

L'instruction yield ne vous donne pas tout ce que vous ne pouviez pas faire en utilisant votre propre implémentation de iterator personnalisée, mais il vous sauve besoin d'écrire le code souvent complexe nécessaire. Il y a très peu de problèmes (le cas échéant) qui ne peuvent pas résoudre plus d'une manière.

Voici quelques questions et réponses plus récentes qui fournissent plus de détails:

Yield keyword value added?

Is yield useful outside of LINQ?

5

en fait je l'utiliser d'une manière non traditionnelle sur mon site IdeaPipe

public override IEnumerator<T> GetEnumerator() 
{ 
    // goes through the collection and only returns the ones that are visible for the current user 
    // this is done at this level instead of the display level so that ideas do not bleed through 
    // on services 
    foreach (T idea in InternalCollection) 
     if (idea.IsViewingAuthorized) 
      yield return idea; 
} 

donc en gros il vérifie si l'affichage l'idée est actuellement autorisé et si c'est il renvoie l'idée. Si ce n'est pas le cas, il est simplement ignoré. Cela me permet de mettre en cache les idées mais d'afficher les idées aux utilisateurs autorisés. Sinon, je devrais les retirer à chaque fois en fonction des permissions, quand elles sont seulement ré-classées toutes les heures.

1

Les opérateurs LINQ de la classe Enumerable sont implémentés comme des itérateurs créés avec l'instruction yield. Il vous permet de chaîner des opérations telles que Select() et Where() sans vraiment énumérer quoi que ce soit jusqu'à ce que vous utilisiez réellement l'énumérateur dans une boucle, généralement en utilisant l'instruction foreach. En outre, étant donné qu'une seule valeur est calculée lorsque vous appelez IEnumerator.MoveNext() si vous décidez d'arrêter la mid-collection, vous économisez l'impact sur les performances du calcul de tous les résultats.

Les itérateurs peuvent également être utilisés pour implémenter d'autres types d'évaluation paresseuse où les expressions sont évaluées uniquement lorsque vous en avez besoin. Vous pouvez également utiliser yield pour plus de choses de fantaisie comme les coroutines.

1

Une autre bonne utilisation pour le rendement est d'effectuer une fonction sur les éléments d'un IEnumerable et de renvoyer un résultat d'un type différent, par exemple:

public delegate T SomeDelegate(K obj); 

public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action) 
{ 
    foreach (var i in list) 
     yield return action(i); 
} 
2

Une utilisation intéressante est comme un mécanisme de programmation asynchrone esp pour les tâches qui prennent plusieurs étapes et nécessitent le même ensemble de données dans chaque étape. Deux exemples de ceci seraient Jeffery Richters AysncEnumerator Part 1 et Part 2. Le Runtime de Concurrency et de Coordination (CCR) utilise également cette technique CCR Iterators. L'utilisation du rendement peut empêcher le downcasting vers un type de béton.

1

C'est pratique pour s'assurer que le consommateur de la collection ne le manipule pas.

0

Vous pouvez également utiliser yield return pour traiter une série de résultats de la fonction comme une liste. Par exemple, considérons une entreprise qui paie ses employés toutes les deux semaines. On pourrait récupérer un sous-ensemble des dates de paie sous forme de liste en utilisant ce code:

void Main() 
{ 
    var StartDate = DateTime.Parse("01/01/2013"); 
    var EndDate = DateTime.Parse("06/30/2013"); 
    foreach (var d in GetPayrollDates(StartDate, EndDate)) { 
     Console.WriteLine(d); 
    } 
} 

// Calculate payroll dates in the given range. 
// Assumes the first date given is a payroll date. 
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int  daysInPeriod = 14) { 
    var thisDate = startDate; 
    while (thisDate < endDate) { 
     yield return thisDate; 
     thisDate = thisDate.AddDays(daysInPeriod); 
    } 
} 
Questions connexes