35 votes

Certains aident à comprendre le "rendement"

Dans mon éternelle quête de sucer moins je garde de heurter le "rendement" de la déclaration.
J'ai essayé d'envelopper ma tête autour de lui un peu de temps maintenant, mais je suis perplexe à chaque fois avec le même message d'erreur.

Il va quelque chose comme ceci:

Le corps de [someMethod] ne peut pas être un itérateur bloc parce que 'Système.Les Collections.Génériques.Liste< Classe>' n'est pas un itérateur type d'interface.

C'est le code où je suis coincé:

        foreach (XElement header in headersXml.Root.Elements()){
            yield return (ParseHeader(header));                
        }

Ce que je fais mal? Je ne peux pas utiliser le rendement dans un itérateur? Alors quel est le point? Dans le cas de l'exemple, il dit que la Liste< ProductMixHeader> n'est pas un type d'interface d'itérateur. ProductMixHeader est une classe personnalisée, mais j'imagine que la Liste est un itérateur type d'interface, non?

--Edit-- Merci à tous pour les réponses rapides. Réponse donnée à la première réponse. Je sais que cette question n'est pas nouvelle et les mêmes ressources de garder popping up. Il s'est avéré que je pensais que je pouvais retourner la Liste un type de retour, mais parce que la Liste n'est pas paresseux, il ne peut pas être utilisé. Changer le type de retour de IEnumerable résolu le problème :D

Maintenant un peu liés à la question (pas la peine d'ouvrir un nouveau fil): est-il utile de donner IENumerable un type de retour si je suis sûr que 99% des cas je vais aller .ToList() de toute façon? Quelles seront les performances de faire pour moi là?

32voto

Lasse V. Karlsen Points 148037

Une méthode utilisant le taux de retour doit être déclaré que le retour de l'une des deux interfaces suivantes:

IEnumerable<SomethingAppropriate>
IEnumerator<SomethingApropriate>

(merci à Jon et Marc pour souligner IEnumerator)

Exemple:

public IEnumerable<AClass> YourMethod()
{
    foreach (XElement header in headersXml.Root.Elements())
    {
        yield return (ParseHeader(header));                
    }
}

le rendement est un paresseux producteur de données, seule la production d'un autre élément après la première a été récupérée, alors que le retour d'une liste sera de retour tout d'un coup.

Donc, il y a une différence, et vous avez besoin de déclarer la méthode correctement.

Pour plus d'informations, lire de Jon réponse ici, qui contient quelques très liens utiles.

15voto

Jon Skeet Points 692016

C'est un sujet délicat. En un mot, c'est une façon simple de mise en œuvre de IEnumerable et de ses amis. Le compilateur crée vous un état de la machine, en transformant les paramètres et les variables locales dans les variables d'instance dans une nouvelle classe. Des choses compliquées.

J'ai un peu de ressources sur ceci:

8voto

Marc Gravell Points 482669

"rendement" crée un bloc itérateur - une classe générée par le compilateur pouvant implémenter IEnumerable[<T>] ou IEnumerator[<T>] . Jon Skeet a une très bonne (et libre discussion) à ce sujet au chapitre 6 de C # in Depth .

Mais fondamentalement, pour utiliser "rendement", votre méthode doit renvoyer IEnumerable[<T>] ou IEnumerator[<T>] . Dans ce cas:

 public IEnumerable<AClass> SomeMethod() {
    // ...
    foreach (XElement header in headersXml.Root.Elements()){
        yield return (ParseHeader(header));                
    }
}
 

3voto

Ian P Points 7930

List implémente Ienumerable.

Voici un exemple qui pourrait nous éclairer sur ce que vous essayez d'apprendre. J'ai écrit ça environ 6 mois

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace YieldReturnTest
{
    public class PrimeFinder
    {
        private Boolean isPrime(int integer)
        {
            if (0 == integer)
                return false;

            if (3 > integer)
                return true;

            for (int i = 2; i < integer; i++)
            {
                if (0 == integer % i)
                    return false;
            }
            return true;
        }

        public IEnumerable<int> FindPrimes()
        {
            int i;

            for (i = 1; i < 2147483647; i++)
            {
                if (isPrime(i))
                {
                    yield return i;
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            PrimeFinder primes = new PrimeFinder();

            foreach (int i in primes.FindPrimes())
            {
                Console.WriteLine(i);
                Console.ReadLine();
            }

            Console.ReadLine();
            Console.ReadLine();
        }
    }
}
 

3voto

Simon Steele Points 8344

Je recommande fortement d’utiliser Reflector pour examiner ce que yield fait réellement pour vous. Vous pourrez voir le code complet de la classe générée par le compilateur lorsqu’il utilisera le rendement, et j’ai constaté que les gens comprenaient le concept beaucoup plus rapidement quand ils pouvaient voir le résultat de bas niveau (ainsi, niveau je suppose).

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