关于收益率的回报,并打破由一个foreach关注 [英] a concern about yield return and breaking from a foreach

查看:149
本文介绍了关于收益率的回报,并打破由一个foreach关注的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有一种合适的方式从一个foreach打破这样了IEnumerable<>知道我做了它应该清理

Is there a proper way to break from a foreach such that the IEnumerable<> knows that I'm done and it should clean up.

考虑以下code:

    private static IEnumerable<Person> getPeople()
    {
        using (SqlConnection sqlConnection = new SqlConnection("..."))
        {
            try
            {
                sqlConnection.Open();
                using (SqlCommand sqlCommand = new SqlCommand("select id, firstName, lastName from people", sqlConnection))
                {

                    using (SqlDataReader reader = sqlCommand.ExecuteReader())
                    {
                        while (reader.Read())
                            yield return new Person(reader.GetGuid(0), reader.GetString(1), reader.GetString(2));
                    }
                }
            }
            finally
            {
                Console.WriteLine("finally disposing of the connection");
                if (sqlConnection.State == System.Data.ConnectionState.Open)
                    sqlConnection.Close();
            }
        }
    }

如果他消费者不从的foreach突破则全部的寄托是好的,读者将返回false,while循环willend和函数清理数据库的命令和连接。但是,如果主叫方在foreach打破我完成之前,会发生什么情况?

If he consumer does not break from the foreach then everthing is fine and the reader will return false, the while loop willend and the function cleans up the database command and connection. But what happens if the caller breaks from the foreach before i'm finished?

推荐答案

非常好的问题。你不必担心这一点;编译器需要照顾它。基本上,我们做的是我们把清理code为finally块进入一个特殊的清理方法所产生的迭代器。当控制离开来电者的的foreach块,编译器生成code的呼吁迭代器清理code。

Excellent question. You do not need to worry about this; the compiler takes care of it for you. Basically, what we do is we put the cleanup code for the finally blocks into a special cleanup method on the generated iterator. When control leaves the caller's foreach block, the compiler generates code which calls the cleanup code on the iterator.

一个简单的例子:

static IEnumerable<int> GetInts()
{
    try { yield return 1; yield return 2;} 
    finally { Cleanup(); }
}

您的问题基本上是是清理()调用这个场景?

Your question is basically "Is Cleanup() called in this scenario?"

foreach(int i in GetInts()) { break; }

是的。迭代器块为一类具有Dispose方法调用清理,然后foreach循环是为类似的事情,以生成生成:

Yes. The iterator block is generated as a class with a Dispose method that calls Cleanup, and then the foreach loop is generated as something similar to:

{
  IEnumerator<int> enumtor = GetInts().GetEnumerator();
  try
  {
    while(enumtor.MoveNext())
    {
      i = enumtor.Current;
      break;
    }
  }
  finally
  {
    enumtor.Dispose();
  }
}

所以,当突破发生,最终接管并处置被调用。

So when the break happens, the finally takes over and the disposer is called.

请参阅我最近的系列文章,如果您想了解一些我们认为在这个功能的设计怪异的极端案例的详细信息。

See my recent series of articles if you want more information about some of the weird corner cases we considered in the design of this feature.

<一个href="http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx">http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx

这篇关于关于收益率的回报,并打破由一个foreach关注的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆