2011-10-13 79 views
4

在下面的测试中,使用yield return时无法使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). 

回答

11

你有实际枚举返回IEnumerable看到输出:

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

当您使用yield return关键字时,编译器将为您构建一个状态机。它的代码只有在你实际使用它迭代返回的枚举时才会运行。

是否有什么特别的原因您试图用yield return打印出string s的序列?这不是真正的功能的目的,这是为了简化序列生成器的创建,而不是枚举已经生成的序列。 foreach是后者的首选方法。

+0

谢谢,我现在明白了。所以调用PrintAllYield只会构造状态机,但是在返回的枚举被迭代时执行主体。 – henginy

+0

@henginy没错。每当你在返回的对象上调用MoveNext()时,它都会运行,直到它达到“yield return”(或“yield break”)。 – dlev

+0

谢谢。顺便说一下,我的实际目的不是打印字符串,而是仅用于调试目的。实际的代码扫描目录并处理它们中的文件。我使用yield return来建立流式执行的管道。 – henginy