使用内收益回报
如果我没记错的话,当我在 using SqlConnection
块中使用产量时,我遇到了运行时异常。
using (var connection = new SqlConnection(connectionString))
{
var command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
yield reader[0];
}
// Call Close when done reading.
reader.Close();
}
当我用一个列表替换 yield
时,这些问题得到了解决,我在每次迭代中添加了项目。
当在 using StreamReader
块内时,同样的问题还没有发生在我身上
using (var streamReader = new StreamReader(fileName))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
yield return line;
}
}
是否有任何解释为什么异常发生在前一种情况而不是后者?这样的施工是否可取?
编辑要获得我过去所做的错误(早期处置),您应该调用下面的第一个方法:
IEnumerable<string> Read(string fileName)
{
using (var streamReader = new StreamReader(fileName))
{
return Read(streamReader);
} // Dispose will be executed before ReadLine() because of deffered execution
}
IEnumerable<string> Read(StreamReader streamReader)
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
yield return line;
}
}
使用其他延迟执行的方法可以实现相同的错误,例如System. Linq.Enumerable.Select()
If I recall correctly that when I used yield inside using SqlConnection
blocks I got runtime exceptions.
using (var connection = new SqlConnection(connectionString))
{
var command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
yield reader[0];
}
// Call Close when done reading.
reader.Close();
}
Those problems were solved when I replaced yield
by a List where I added items each iteration.
The same problem didn't happen yet to me when inside using StreamReader
blocks
using (var streamReader = new StreamReader(fileName))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
yield return line;
}
}
Is there any explanation why Exceptions happened in the former case and not in the latter? Is this construction advisable?
EDIT To get the error (early disposal) that I did in the past you should call the first method below:
IEnumerable<string> Read(string fileName)
{
using (var streamReader = new StreamReader(fileName))
{
return Read(streamReader);
} // Dispose will be executed before ReadLine() because of deffered execution
}
IEnumerable<string> Read(StreamReader streamReader)
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
yield return line;
}
}
The same error can be achieved with other ways of deferring execution, such as System.Linq.Enumerable.Select()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请参阅这篇文章以获得很好的解释
using
和yield
的问题。因为您在枚举器中返回,所以 using 块在访问任何内容之前就已经销毁了上下文。答案有很好的解决方案,基本上,要么使包装器方法成为枚举器,要么构建一个列表。此外,在读取器周围使用
using
(而不是连接)通常更实用,并使用CommandBehavior.CloseConnection
来确保读取器完成时释放资源。尽管这在您的情况下并不重要,但如果您从方法返回数据读取器,这将确保在处理读取器时正确关闭连接。See this post for a good explanation of the issues with
using
andyield
. Because you return in enumerator, the using block will already have destroyed the context before anything is accessed. The answers have good solutions, basically, either make the wrapper method an enumerator, or build a list instead.Also it's usually more practical to have
using
around the reader, not the connection, and useCommandBehavior.CloseConnection
to ensure resources are released when the reader's done. Though it doesn't really matter in your situation, if you ever return a data reader from a method, this will ensure the connection is closed properly when the reader is disposed.在这两种情况下,编译器都应该正确处理
using
块内的yield
。没有明显的理由说明为什么它应该抛出异常。需要注意的一件事是,只有在完成迭代和/或手动处置枚举器对象后,连接才会被处置。如果您在公共方法中公开此代码,那么愚蠢或恶意代码可能会使您的连接长时间保持打开状态:
The compiler should handle the
yield
inside theusing
block correctly in both cases. There's no obvious reason why it should throw an exception.One thing to be aware of is that the connection will only be disposed once you've completed iterating and/or manually disposed the enumerator object. If you expose this code in a public method then it's possible that stupid or malicious code could keep your connection open for a long time: