使用yield return时未调用的方法

时间:2010-04-16 11:54:19

标签: c#-2.0 yield-return

我在使用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"]);
    }    
}

以上代码永远不会运行,当调用此方法时,它只是跨过它。

但是,如果我改为......

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

它运作得很好。

我不明白为什么第一种方法永远不会运行,你能帮助我理解这里发生的事情吗?

3 个答案:

答案 0 :(得分:7)

当调用者实际开始枚举返回的集合时,“yield”版本才会“运行”。

例如,如果您只获得该集合:

var results = SomeObject.SomeMethod (5);

并且不对其执行任何操作,SomeMethod将无法执行。

只有当您开始枚举results集合时,它才会点击。

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

答案 1 :(得分:2)

yield return方法实际上被转换为状态机类,可以懒惰地检索信息 - 只有当你真正要求它时。这意味着,为了实际提取数据,您必须迭代方法的结果。

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

它在第二种情况下运行的原因是因为没有yield块,因此整个方法一次运行。

在这种特定情况下,使用迭代器块比使用常规块更有利,因为GetClassesFromDb()也不是。这意味着它将在第一次运行时同时检索所有数据。当您可以一次访问一个项目时,最好使用迭代器块,因为如果您不再需要它们,就可以停止。

答案 2 :(得分:0)

当我决定让我们公司的解析器懒洋洋地读取传入数据时,我必须以近乎灾难性的方式学习有多酷/危险yield。幸运的是,我们的一些实现函数中只有一个实际使用了yield关键字。花了几天才意识到它根本没有做任何工作。

yield关键字尽可能是懒惰的,包括如果你不想使用.ToList().FirstOrDefault()或{{{{}}这样的方法,则完全跳过该方法1}}

以下是两个变体,一个使用关键字,一个返回直接列表。一个人甚至不愿意执行,而另一个人会这样做,即使它们看起来是一样的。

.Any()

故事的道德:确保如果有一个返回IEnumerable的方法,并且在该方法中使用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; } } ,那么你会有一些东西会迭代结果,或者方法不会在所有