2010-04-16 28 views
5

estoy teniendo un pequeño problema con un método en el que yo uso yield return esto no funciona ...método no se llama cuando se utiliza 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"]); 
    }  
} 

El código anterior no funciona, cuando la llamada es hecho a este método solo lo pasa por alto.

Sin embargo si cambio a ...

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; 
} 

Funciona muy bien.

No entiendo por qué el primer método no funciona, usted me podría ayudar en la comprensión de lo que está sucediendo aquí?

+0

¿Cómo se llama el método? – gammelgul

+0

Llamar a un constructor como este: 'Prop = SomeMethod (param);' – DaveParsons

Respuesta

7

La versión "rendimiento" sólo "correr" cuando la persona que llama en realidad comienza a enumerar la colección devuelta.

Si, por ejemplo, que sólo recibe la colección:

var results = SomeObject.SomeMethod (5); 

y no hace nada con ella, la SomeMethod no se ejecute. Sólo

cuando se inicia la enumeración de la colección results, que llegará.

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

Brillante, ¡exactamente lo que necesitaba saber! Gracias – DaveParsons

2

yield return métodos se convierte realmente en clases de máquinas de estados que recuperan información perezosamente - sólo cuando en realidad se lo solicita. Eso significa que con el fin de sacar realmente los datos, hay que iterar sobre el resultado de su método.

// Gives you an iterator object that hasn't done anything yet 
IEnumerable<MyClass> list = SomeMethod(); 

// Enumerate over the object 
foreach (var item in list) { 
    // Only here will the data be retrieved. 
    // The method will stop on yield return every time the foreach loops. 
} 

La razón por la que se ejecuta en el segundo caso se debe a que no hay ningún bloque de rendimiento y, por lo tanto, todo el método se ejecuta de una sola vez.

En este caso específico, es poco probable que tenga alguna ventaja al usar un bloque iterador sobre uno normal porque su GetClassesFromDb() tampoco lo es. Esto significa que recuperará todos los datos al mismo tiempo la primera vez que se ejecuta. iterador bloques son los más utilizados cuando se puede acceder a los elementos de uno en uno, porque de esa manera se puede detener si no los necesita más.

0

Tuve que aprender de una manera casi desastrosa lo genial/peligroso yield es cuando decidí hacer que el analizador de nuestra compañía leyera los datos entrantes perezosamente. Afortunadamente, solo una de nuestras pocas funciones de implementación usó realmente la palabra clave yield. Tomó unos días darse cuenta de que no estaba haciendo ningún trabajo en absoluto.

La palabra clave de rendimiento que será tan vago como sea posible, incluyendo saltando sobre el método por completo si no se pone a trabajar con algo como .ToList() o .FirstOrDefault() o .Any()

A continuación se presentan dos variantes, una usando la palabra clave y uno que devuelve una lista recta. Uno ni siquiera se molestan en ejecución, mientras que el otro, a pesar de que parecen la misma.

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; 
    } 
} 

Moraleja de la historia: Asegúrese de que si tienen un método que devuelve IEnumerable y utiliza yield en ese método, usted tiene algo que va a iterar sobre los resultados, o el método no se ejecutará en absoluto.

Cuestiones relacionadas