我在使用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;
}
它运作得很好。
我不明白为什么第一种方法永远不会运行,你能帮助我理解这里发生的事情吗?
答案 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;
}
}
,那么你会有一些东西会迭代结果,或者方法不会在所有