不使用,foreach或手动调用Dispose()时的枚举器处理

Oli*_*ver 6 c# enumeration enumerator yield-return

我正在使用yield return迭代SqlDataReader记录:

IEnumerable<Reading> GetReadings() {
    using (var connection = new SqlConnection(_connectionString))
    {
        using (var command = new SqlCommand(_query, connection))
        {
            connection.Open();
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return new Reading
                    {
                        End = reader.GetDateTime(0),
                        Value = reader.GetDouble(1)
                    };
                }
            }
            connection.Close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我使用这个被接受的答案的改编版本来"拉"许多迭代器:

   var enumerators = data.Select(d => new
   {
       d.Key,
       Enumerator = d.Value.GetEnumerator()
   }).ToList();

   while (true)
   {
       foreach (var item in enumerators)
       {
           if (!item.Enumerator.MoveNext())
           {
               yield break;
           }

           /*snip*/
       }

      /*snip*/
   }
Run Code Online (Sandbox Code Playgroud)

在上面的方法中,Dispose()没有显式调用枚举器,并且因为它们未在usingor foreach语句中使用,底层迭代器是否会保持打开状态?在我打开的情况下SqlConnection.

我是否应该呼吁Dispose()调查员确保整个下游链关闭?

Eri*_*ert 19

枚举这个迭代器时,如果枚举器Dispose()未被显式调用,并且未在using语句中使用,那么底层迭代器是否会保持打开状态?

让我重新将这个问题改成一个更容易回答的形式.

当使用foreach通过包含using语句的迭代器块进行枚举时,控件离开循环时是否会释放资源?

是.

什么机制确保这一点?

这三个:

  • 一个using说法是只写一个方便的方法try-finally,其中finally资源的处置.

  • foreach回路为方便语法try-finally,并再次,在finally通话Dispose时控制叶枚举循环.

  • 由迭代器块生成的枚举器实现IDisposable.调用Dispose()它可确保finally执行迭代器块中的所有块,包括finally来自using语句的块.

如果我避免foreach循环,调用GetEnumerator自己,并且不调用Dispose枚举器,我是否保证finally枚举器的块将运行?

不. 始终处置您的普查员.他们实施IDisposable是有原因的.

那现在清楚了吗?

如果这个主题感兴趣,那么你应该阅读我关于C#中迭代器块的设计特征的长篇系列.

http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/