2010-04-16 13 views
5

Je vais avoir un peu de mal avec une méthode dans laquelle j'utilise yield return cela ne fonctionne pas ...Méthode non appelée lors de l'utilisation yield return

public IEnumerable<MyClass> SomeMethod(int aParam) 
{ 
    foreach(DataRow row in GetClassesFromDB(aParam).Rows) 
    { 
     yield return new MyClass((int)row["Id"], (string)row["SomeString"]); 
    }  
} 

Le code ci-dessus ne fonctionne jamais, lorsque l'appel est fait à cette méthode, il passe juste dessus.

Cependant si je change de ...

public IEnumerable<MyClass> SomeMethod(int aParam) 
{ 
    IList<MyClass> classes = new List<MyClass>(); 

    foreach(DataRow row in GetClassesFromDB(aParam).Rows) 
    { 
     classes.Add(new MyClass((int)rows["Id"], (string)row["SomeString"]); 
    } 

    return classes; 
} 

Il fonctionne très bien. Je ne comprends pas pourquoi la première méthode ne fonctionne jamais, pourriez-vous m'aider à comprendre ce qui se passe ici?

+0

Comment appelez-vous la méthode? – gammelgul

+0

Appel dans un constructeur comme ceci: 'Prop = SomeMethod (param);' – DaveParsons

Répondre

7

La version "yield" est seulement "exécutée" lorsque l'appelant commence réellement à énumérer la collection retournée.

Si, par exemple, vous obtenez seulement la collection:

var results = SomeObject.SomeMethod (5); 

et ne faites rien avec elle, la SomeMethod ne sera pas exécutée.

Seulement lorsque vous commencez à énumérer la collection results, il va frapper.

foreach (MyClass c in results) 
{ 
    /* Now it strikes */ 
} 
+0

Brillant, exactement ce que j'avais besoin de savoir! Je vous remercie – DaveParsons

2

yield return méthodes sont effectivement converties en classes de machine d'état qui extraient des informations paresseusement - que lorsque vous demandez en fait pour cela. Cela signifie que pour extraire des données, vous devez parcourir le résultat de votre méthode. La raison pour laquelle il s'exécute dans le second cas est parce qu'il n'y a pas de bloc de rendement, et donc la méthode entière s'exécute en une seule fois.

Dans ce cas précis, il est peu probable que vous ayez un avantage à utiliser un bloc d'itérateur par rapport à un bloc normal, car votre GetClassesFromDb() ne l'est pas non plus. Cela signifie qu'il va récupérer toutes les données en même temps la première fois qu'il s'exécute. Les blocs d'itérateur sont mieux utilisés lorsque vous pouvez accéder aux éléments un à la fois, car vous pouvez ainsi vous arrêter si vous n'en avez plus besoin.

0

J'ai dû apprendre d'une manière presque désastreuse comment cool/dangereux yield est quand j'ai décidé de faire lire paresseusement les données entrantes par notre analyseur de l'entreprise. Heureusement, seule une poignée de nos fonctions d'implémentation a réellement utilisé le mot-clé yield. J'ai pris quelques jours pour me rendre compte que ça ne faisait aucun travail.

Le mot-clé yield il sera aussi paresseux que possible éventuellement, y compris sauter sur la méthode tout à fait si vous ne mettez pas à travailler avec quelque chose comme .ToList() ou .FirstOrDefault() ou .Any()

Voici deux variantes, une en utilisant le mot-clé et un retournant une liste directe. L'un ne prendra même pas la peine d'exécuter, tandis que l'autre le fera, même s'ils semblent identiques.

public class WhatDoesYieldDo 
{ 
    public List<string> YieldTestResults; 

    public List<string> ListTestResults; 

    [TestMethod] 
    public void TestMethod1() 
    { 
     ListTest(); 
     Assert.IsTrue(ListTestResults.Any()); 

     YieldTest(); 
     Assert.IsTrue(YieldTestResults.Any()); 
    } 

    public IEnumerable<string> YieldTest() 
    { 
     YieldTestResults = new List<string>(); 
     for (var i = 0; i < 10; i++) 
     { 
      YieldTestResults.Add(i.ToString(CultureInfo.InvariantCulture)); 
      yield return i.ToString(CultureInfo.InvariantCulture); 
     } 
    } 

    public IEnumerable<string> ListTest() 
    { 
     ListTestResults = new List<string>(); 

     for (var i = 0; i < 10; i++) 
     { 
      ListTestResults.Add(i.ToString(CultureInfo.InvariantCulture)); 
     } 

     return ListTestResults; 
    } 
} 

Morale de l'histoire: Assurez-vous que si une méthode qui retourne IEnumerable et que vous utilisez yield dans cette méthode, vous avez quelque chose qui va itérer sur les résultats, ou la méthode n'exécutera pas du tout.

Questions connexes