Method not called when using yield return

僤鯓⒐⒋嵵緔 提交于 2020-01-11 08:26:14

问题


I'm having a little trouble with a method in which I use yield return this doesn't work...

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

The above code never runs, when the call is made to this method it just steps over it.

However if I change to...

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

It works just fine.

I don't understand why the first method never runs, could you help me in understanding what is happening here?


回答1:


The "yield" version is only "run" when the caller actually starts to enumerate the returned collection.

If, for instance, you only get the collection:

var results = SomeObject.SomeMethod (5);

and don't do anything with it, the SomeMethod will not execute.

Only when you start enumerating the results collection, it will hit.

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



回答2:


yield return methods are actually converted into state machine classes that retrieve information lazily - only when you actually ask for it. That means that in order to actually pull data, you have to iterate over the result of your method.

// 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.
}

The reason it runs in the second case is because there's no yield block, and thus the entire method runs in one go.

In this specific case, it's unlikely that you'll have any advantage to use an iterator block over a regular one because your GetClassesFromDb() isn't one either. This means that it will retrieve all the data at the same time first time it runs. Iterator blocks are best used when you can access items one at a time, because that way you can stop if you don't need them anymore.




回答3:


I had to learn in a near disastrous way how cool/dangerous yield is when I decided to make our company's parser read incoming data lazily. Fortunately only one of the handful of our implementing functions actually used the yield keyword. Took a few days to realize it was quietly not doing any work at all.

The yield keyword it will be as lazy as it possibly can, including skipping over the method altogether if you don't put it to work with something like .ToList() or .FirstOrDefault() or .Any()

Below are two variations, one using the keyword and one returning a straight-up list. One won't even bother to execute, while the other will, even though they seem the same.

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

Moral of the story: Make sure that if have a method that returns IEnumerable and you use yield in that method, you have something that will iterate over the results, or the method won't execute at all.



来源:https://stackoverflow.com/questions/2652656/method-not-called-when-using-yield-return

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!