我有以下代码。查询需要大约30秒才能执行。我发现每次using
尝试枚举迭代器时都会调用顶部for each
块。在枚举器中对MoveNext
的每次调用执行哪个均值查询。
那么为什么懒惰的评估会一遍又一遍地重新using
。我知道工作,但我需要了解这个目的。
private IEnumerable<FriendProfile> GetProfiles() {
var query = @"
SELECT VirtualNumber, City, Gender, Nick, Age
FROM Profiles
WHERE Not VirtualNumber In ( SELECT VirtualNumber FROM Messages)
ORDER BY Id DESC;";
using (var con = GetConnection()) {
using (var cmd = dbconnection.CreateCommand()) {
cmd.CommandText = query;
var reader = cmd.ExecuteReader();
while (reader.Read()) {
var fp = new FriendProfile();
fp.VirtualNumber = reader.GetString(0);
fp.City = reader.GetString(1);
fp.Gender = reader.GetString(2);
fp.Nick = reader.GetString(3);
fp.Age = reader.GetInt16(4).ToString();
yield return fp;
}
}
}
}
foreach(var fp in GetProfiles()){
.... //foreach item using(){} in GetProfile() is reinitializes. All usings blocks
}
答案 0 :(得分:4)
我不是100%确定你指的是哪个使用块,但如果我理解正确,那么你所说的不应该发生。 yield
将从GetProfiles()
方法返回执行控制权,但yield
之后的代码(即using
块的结尾)将不会被执行,直到while
条件为false
。
以下是一个应该演示此行为的简单示例:
使用此类显示using
块结束的时间:
public class Disposable : IDisposable
{
private readonly string name;
public Disposable(string name)
{
this.name = name;
}
public void Dispose()
{
Console.WriteLine("Disposing of {0}", name);
}
}
和这段代码:
private IEnumerable<int> Test()
{
using (new Disposable("outer"))
{
using (new Disposable("inner"))
{
for (int i = 0; i < 10; i++)
{
yield return i;
}
}
}
}
...
foreach (int i in Test())
{
Console.WriteLine("item {0}", i);
}
输出结果为:
item 0 item 1 item 2 item 3 item 4 item 5 item 6 item 7 item 8 item 9 disposing of inner disposing of outer
这表明using
块在for
循环退出之前不会退出。
答案 1 :(得分:0)
这是因为编译yield
的方式。它实际上是对为实现由GetProfiles()
方法定义的集合而创建的类的迭代调用。 MoveNext()
中每个步骤都会调用foreach
一次{{1}}。 This是对幕后发生的事情的一个不错的介绍。