使用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;
}
它工作得很好。
我不明白为什么第一个方法永远不会运行,你能帮助我理解这里发生了什么吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
“yield”版本仅在调用者实际开始枚举返回的集合时“运行”。
例如,如果您只获取集合:
并且不对其执行任何操作,则
SomeMethod
将不会执行。仅当您开始枚举
results
集合时,它才会命中。The "yield" version is only "run" when the caller actually starts to enumerate the returned collection.
If, for instance, you only get the collection:
and don't do anything with it, the
SomeMethod
will not execute.Only when you start enumerating the
results
collection, it will hit.yield return
方法实际上被转换为延迟检索信息的状态机类 - 仅当您实际请求时。这意味着为了实际提取数据,您必须迭代方法的结果。它在第二种情况下运行的原因是因为没有yield块,因此整个方法一次性运行。
在这种特定情况下,与常规迭代器块相比,使用迭代器块不太可能有任何优势,因为您的
GetClassesFromDb()
也不是迭代器块。这意味着它将在第一次运行时同时检索所有数据。当您一次可以访问一个项目时,最好使用迭代器块,因为这样您就可以在不再需要它们时停止。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.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.当我决定让我们公司的解析器延迟读取传入数据时,我不得不以近乎灾难性的方式了解到
yield
是多么酷/危险。幸运的是,我们的少数实现函数中只有一个实际使用了yield 关键字。花了几天时间才意识到它根本没有做任何工作。Yield 关键字将尽可能地惰性,包括如果您不将其与
.ToList()
或.FirstOrDefault() 等方法一起使用,则完全跳过该方法
或.Any()
下面是两种变体,一种使用关键字,另一种返回直接列表。一个人甚至懒得去执行,而另一个人却会,尽管它们看起来是一样的。
这个故事的寓意是:如果有一个返回 IEnumerable 的方法,并且您在该方法中使用了yield,那么请确保您有一些可以迭代结果的方法,否则该方法根本不会执行。
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.
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.