使用yield 迭代datareader 可能不会关闭连接?
这是一个示例代码,用于使用我在谷歌搜索时在一些地方找到的yield关键字从数据库检索数据:
public IEnumerable<object> ExecuteSelect(string commandText)
{
using (IDbConnection connection = CreateConnection())
{
using (IDbCommand cmd = CreateCommand(commandText, connection))
{
connection.Open();
using (IDbDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
yield return reader["SomeField"];
}
}
connection.Close();
}
}
}
我是否正确地认为,在这个示例代码中,如果我们不迭代,连接就不会关闭整个数据读取器?
如果我正确理解了收益,这里是一个不会关闭连接的示例。
foreach(object obj in ExecuteSelect(commandText))
{
break;
}
对于可能不是灾难性的数据库连接,我想 GC 最终会清理它,但是如果它不是一个连接,而是一个更关键的连接呢?资源?
Here is a sample code to retrieve data from a database using the yield keyword that I found in a few place while googling around :
public IEnumerable<object> ExecuteSelect(string commandText)
{
using (IDbConnection connection = CreateConnection())
{
using (IDbCommand cmd = CreateCommand(commandText, connection))
{
connection.Open();
using (IDbDataReader reader = cmd.ExecuteReader())
{
while(reader.Read())
{
yield return reader["SomeField"];
}
}
connection.Close();
}
}
}
Am I correct in thinking that in this sample code, the connection would not be closed if we do not iterate over the whole datareader ?
Here is an example that would not close the connection, if I understand yield correctly..
foreach(object obj in ExecuteSelect(commandText))
{
break;
}
For a db connection that might not be catastrophic, I suppose the GC would clean it up eventually, but what if instead of a connection it was a more critical resource?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
编译器综合的 Iterator 实现了
IDisposable
,当退出foreach
循环时foreach
会调用它。迭代器的
Dispose()
方法将在提前退出时清理using
语句。只要您在
foreach
循环、using()
块中使用迭代器,或以其他方式调用Dispose()
方法,将会发生迭代器的清理。The Iterator that the compiler synthesises implements
IDisposable
, whichforeach
calls when theforeach
loop is exited.The Iterator's
Dispose()
method will clean up theusing
statements on early exit.As long as you use the iterator in a
foreach
loop,using()
block, or call theDispose()
method in some other way, the cleanup of the Iterator will happen.连接将自动关闭,因为您在“using”块内使用它。
Connection will be closed automatically since you're using it inside "using" block.
从我尝试过的简单测试来看,aku 是对的,一旦 foreach 块退出,就会调用 dispose。
@David:但是调用堆栈在调用之间保留,因此连接不会关闭,因为在下一次调用时,我们将返回到yield之后的下一条指令,即while块。
我的理解是,当迭代器被释放时,连接也会随之被释放。 我还认为不需要 Connection.Close,因为当由于 using 子句而处置对象时,它将被处理。
这是我尝试测试行为的一个简单程序......
From the simple test I have tried, aku is right, dispose is called as soon as the foreach block exit.
@David : However call stack is kept between call, so the connection would not be closed because on the next call we would return to the next instruction after the yield, which is the while block.
My understanding is that when the iterator is disposed, the connection would also be disposed with it. I also think that the Connection.Close would not be needed because it would be taken care of when the object is disposed because of the using clause.
Here is a simple program I tried to test the behavior...
从此技术说明来看,您的代码将不会按预期工作,但中止第二项,因为返回第一项时连接已关闭。
@Joel Gauvreau:是的,我应该继续读下去。 本系列的第 3 部分解释了编译器添加对finally 块的特殊处理仅在真实结束时触发。
Judging from this technical explanation, your code will not work as expected, but abort on the second item, because the connection was already closed when returning the first item.
@Joel Gauvreau : Yes, I should have read on. Part 3 of this series explains that the compiler adds special handling for finally blocks to trigger only at the real end.