Подтвердить что ты не робот

При использовании yield в операторе "using", когда происходит Dispose?

У меня есть вопрос относительно отложенного выполнения и удаления данных.

Рассмотрим следующий пример:

private IEnumerable<string> ParseFile(string fileName)
{
    using(StreamReader sr = new StreamReader(fileName))
    {
        string line;
        while((line = sr.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

private void LineReader(string fileName)
{
    int counter = 0;

    foreach(string line in ParseFile(fileName))
    {
        if(counter == 2)
        {
            break; // will this cause a dispose on the StreamReader?
        } else
        {
            Console.WriteLine(line);
            counter++;
        }
    }
}

Будет ли оператор break сразу заставлять читателя в ParseFile удалять или он все еще рассматривается в контексте и блокирует файл открытым до тех пор, пока сама программа не будет закрыта?

4b9b3361

Ответ 1

Итак, у нас есть несколько отдельных вопросов, которые здесь происходят.

Прежде всего, рассмотрим using в блоке итератора. IEnumerator продолжается IDisposable. Код, который генерирует блоки итератора, на самом деле достаточно прост, что любые блоки try/finally (a using приводит к созданию блока try/finally) приводит к тому, что содержимое блока finally вызывается в методе Dispose перечислитель, если он еще не был вызван. До тех пор, пока вызывается перечислитель, он не пропустит StreamReader.

Итак, теперь мы спрашиваем себя, находится ли перечислитель. Все операторы foreach вызывают Dispose в перечислителе (если он реализует IDisposable). Они делают это, даже если вы выходите с помощью инструкции break или return, а также когда она заканчивается нормально.

Таким образом, вы можете быть уверены, что при любых обстоятельствах ресурс не будет просачиваться, запрещая случаи, когда ничто не может быть предотвращено от утечки (то есть кто-то, который отталкивает машину).