Не може да се печата в конзолата чрез връщане на добива

В тестовете по-долу не мога да накарам Console.WriteLine наистина да отпечата, когато използвам връщане на добива. Експериментирам с възвръщаемост на дохода и разбирам, че нещо ми липсва в разбирането ми за това, но не мога да разбера какво е то. Защо низовете не се отпечатват вътре в 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 за отпечатване на последователност от strings? Това всъщност не е целта на функцията, която е да опрости създаването на генератори на последователности, а не изброяването на вече генерирана последователност. 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