2010-05-03 130 views

回答

13

收益实现直到需要时才会到达代码。

例如,下面的代码:

public IEnumerable<int> GetInts() 
{ 
    yield return 1; 
    yield return 2; 
    yield return 3; 
} 

将实际编译成执行IEnumerable<int>GetInts()身体会返回一个类的实例嵌套类。

使用反射镜可以看到:

public IEnumerable<int> GetInts() 
{ 
    <GetInts>d__6d d__d = new <GetInts>d__6d(-2); 
    d__d.<>4__this = this; 
    return d__d; 
} 

编辑 - 增加更多的信息关于GetInts实现:
此实现使得懒惰是基于EnumeratorMoveNext()方法的方式。生成可枚举的嵌套类(示例中的<GetInts>d__6d)时,它具有一个状态,并且每个状态都连接一个值(这是一个简单的例子,在更高级的情况下,代码到达状态时将评估该值)。如果我们采取的<GetInts>d__6dMoveNext()代码一看,我们会看到状态:

private bool MoveNext() 
{ 
    switch (this.<>1__state) 
    { 
     case 0: 
      this.<>1__state = -1; 
      this.<>2__current = 1; 
      this.<>1__state = 1; 
      return true; 

     case 1: 
      this.<>1__state = -1; 
      this.<>2__current = 2; 
      this.<>1__state = 2; 
      return true; 

     case 2: 
      this.<>1__state = -1; 
      this.<>2__current = 3; 
      this.<>1__state = 3; 
      return true; 

     case 3: 
      this.<>1__state = -1; 
      break; 
    } 
    return false; 
} 

当枚举被要求为当前对象返回连接到当前状态的对象。

为了表明,只有当它需要你可以看看下面这个例子的代码进行评估:

[TestFixture] 
public class YieldExample 
{ 
    private int flag = 0; 
    public IEnumerable<int> GetInts() 
    { 
     yield return 1; 
     flag = 1; 
     yield return 2; 
     flag = 2; 
     yield return 3; 
     flag = 3; 
    } 

    [Test] 
    public void Test() 
    { 
     int expectedFlag = 0; 
     foreach (var i in GetInts()) 
     { 
      Assert.That(flag, Is.EqualTo(expectedFlag)); 
      expectedFlag++; 
     } 

     Assert.That(flag, Is.EqualTo(expectedFlag)); 
    } 
} 

我希望这是更清晰一点。我建议使用Reflector来查看代码,并在更改“yield”代码时观察编译的代码。

+0

@Elisha:请提供关于GetInts()的更多详细信息。 – 2010-05-03 10:53:54

+0

@masoud ramezani,增加了关于GetInts嵌套枚举类的更多信息。 – Elisha 2010-05-03 13:52:38

+0

谢谢你的完整答案。 – 2010-05-03 14:22:36

4

基本上迭代器使用yield语句implementated被编译成一个实现state machine类。

如果您从不foreach(=迭代并实际使用)返回的IEnumerable<T>,代码永远不会实际执行。如果你这样做,只需要确定下一个返回值所需的最小代码就可以执行,只有当请求下一个值时才能恢复执行。

当您在调试器中单步执行此类代码时,您实际上可以看到此行为发生。至少尝试一次:我认为这是一步一步发生的。