Невозможно вывести на консоль с помощью yield return

В приведенных ниже тестах я не могу заставить Console.WriteLine действительно печатать при использовании yield return. Я экспериментирую с возвратом доходности, и я понимаю, что мне чего-то не хватает в моем понимании этого, но не могу понять, что это такое. Почему строки не печатаются внутри PrintAllYield?

Код:

class Misc1 {
    public IEnumerable<string> PrintAllYield(IEnumerable<string> list) {
        foreach(string s in list) {
            Console.WriteLine(s); // doesn't print 
            yield return s;
        }
    }
    public void PrintAll(IEnumerable<string> list) {
        foreach(string s in list) {
            Console.WriteLine(s); // surely prints OK
        }
    }
}

Тестовое задание:

[TestFixture]
class MiscTests {
    [Test]
    public void YieldTest() {
        string[] list = new[] { "foo", "bar" };
        Misc1 test = new Misc1();

        Console.WriteLine("Start PrintAllYield");
        test.PrintAllYield(list);
        Console.WriteLine("End PrintAllYield");

        Console.WriteLine();

        Console.WriteLine("Start PrintAll");
        test.PrintAll(list);
        Console.WriteLine("End PrintAll");
    }
}

Выход:

Start PrintAllYield
End PrintAllYield

Start PrintAll
foo
bar
End PrintAll

1 passed, 0 failed, 0 skipped, took 0,39 seconds (NUnit 2.5.5).

person henginy    schedule 13.10.2011    source источник


Ответы (1)


Вы должны фактически перечислить возвращенный IEnumerable, чтобы увидеть вывод:

    Console.WriteLine("Start PrintAllYield");
    foreach (var blah in test.PrintAllYield(list))
        ; // Do nothing
    Console.WriteLine("End PrintAllYield");

Когда вы используете ключевое слово yield return, компилятор создаст для вас конечный автомат. Его код будет запущен только тогда, когда вы действительно используете его для итерации возвращаемого перечисляемого.

Есть ли особая причина, по которой вы пытаетесь использовать yield return для вывода последовательности string? На самом деле цель этой функции не в этом, а в том, чтобы упростить создание генераторов последовательностей, а не перечисление уже сгенерированной последовательности. foreach является предпочтительным методом для последнего.

person dlev    schedule 13.10.2011
comment
Спасибо, теперь я понимаю. Таким образом, вызов PrintAllYield создает только конечный автомат, но тело выполняется при повторении возвращаемого перечисляемого. - person henginy; 13.10.2011
comment
@henginy Точно. Каждый раз, когда вы вызываете MoveNext() для возвращаемого объекта, он будет выполняться до тех пор, пока не встретит yield return (или yield break). - person dlev; 13.10.2011
comment
Спасибо. Кстати, моя реальная цель не печатать строки, это было только для целей отладки. Фактический код сканирует каталоги и обрабатывает файлы в них. Я использовал yield return, чтобы установить канал для потокового выполнения. - person henginy; 13.10.2011