收益率内部使用率

问题描述

| 如果我没记错的话,当我在
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