问题描述
|
如果我没记错的话,当我在
using sqlConnection
块内使用yield时,我会遇到运行时异常。
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();
}
当我用一个List替换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;
}
}
可以通过其他推迟执行的方式来实现相同的错误,例如“ 6”解决方法
有关this7ѭ和
yield
问题的详细说明,请参见这篇文章。因为返回枚举数,所以using块在访问任何内容之前已经破坏了上下文。答案有很好的解决方案,基本上,可以将wrapper方法用作枚举器,或者构建一个列表。
另外,通常在阅读器周围放置ѭ7(而不是连接),并使用ѭ10来确保阅读器完成后释放资源,通常更为实用。尽管在您的情况下并不重要,但是如果您曾经从方法中返回数据读取器,这将确保在处理读取器时正确关闭连接。
using(SqlDataReader reader =
command.ExecuteReader(CommandBehavior.CloseConnection)) {
while (reader.Read())
{
yield reader[0];
}
}
,在这两种情况下,编译器均应正确处理using
块内的yield
。没有明显的理由应该引发异常。
要注意的一件事是,只有在完成迭代和/或手动布置枚举器对象后,才会释放该连接。如果您以公共方法公开此代码,那么愚蠢或恶意的代码很可能会使您的连接长时间保持打开状态:
var enumerable = YourMethodThatYieldsFromTheDataReader();
var enumerator = enumerable.GetEnumerator();
enumerator.MoveNext();
Thread.Sleep(forever); // your connection will never be disposed