C#:如何翻译Yield关键字

C#: How to translate the Yield Keyword

百万千克1如果没有yield关键字,msdn示例会是什么样子?如果你表现出色,你可以用任何例子。我只想知道引擎盖下面发生了什么。百万千克1百万千克1收益率运算符的评估是积极的还是迟缓的?百万千克1

样品:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections;
public class List
{
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        while (counter++ < exponent)
        {
            result = result * number;
            yield return result;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0}", i);
        }
    }
}
    百万千克1msdn-yield关键字百万千克1

如果对收益率运算符进行热切评估,我的猜测是:

1
2
3
4
5
6
7
8
9
10
11
12
    public static IEnumerable Power(int number, int exponent)
    {
        int counter = 0;
        int result = 1;
        List<int> powers;
        while (counter++ < exponent)
        {
            result = result * number;
            powers.add(result);
        }
        return powers;
    }

我不知道如果对yield操作符进行惰性评估会是什么样子。

更新:Reflector给出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class List
{
    // Methods
    public List();
    private static void Main();
    public static IEnumerable Power(int number, int exponent);

    // Nested Types
    [CompilerGenerated]
    private sealed class <Power>d__0 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
    {
        // Fields
        private int <>1__state;
        private object <>2__current;
        public int <>3__exponent;
        public int <>3__number;
        private int <>l__initialThreadId;
        public int <counter>5__1;
        public int <result>5__2;
        public int exponent;
        public int number;

        // Methods
        [DebuggerHidden]
        public <Power>d__0(int <>1__state);
        private bool MoveNext();
        [DebuggerHidden]
        IEnumerator<object> IEnumerable<object>.GetEnumerator();
        [DebuggerHidden]
        IEnumerator IEnumerable.GetEnumerator();
        [DebuggerHidden]
        void IEnumerator.Reset();
        void IDisposable.Dispose();

        // Properties
        object IEnumerator<object>.Current { [DebuggerHidden] get; }
        object IEnumerator.Current { [DebuggerHidden] get; }
    }
}

IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
    List.<Power>d__0 d__;
    if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))
    {
        this.<>1__state = 0;
        d__ = this;
    }
    else
    {
        d__ = new List.<Power>d__0(0);
    }
    d__.number = this.<>3__number;
    d__.exponent = this.<>3__exponent;
    return d__;
}



private bool MoveNext()
{
    switch (this.<>1__state)
    {
        case 0:
            this.<>1__state = -1;
            this.<counter>5__1 = 0;
            this.<result>5__2 = 1;
            while (this.<counter>5__1++ < this.exponent)
            {
                this.<result>5__2 *= this.number;
                this.<>2__current = this.<result>5__2;
                this.<>1__state = 1;
                return true;
            Label_0065:
                this.<>1__state = -1;
            }
            break;

        case 1:
            goto Label_0065;
    }
    return false;
}


首先,yield不是一个运算符。收益率回报和收益率中断是一种陈述。

有很多关于编译器如何实现迭代器块的文章。首先阅读关于迭代器块的C规范部分;它给出了一些关于C的实现者可能希望如何进行的建议。

接下来阅读Raymond Chen的系列文章"C语言中迭代器的实现及其后果"

http://www.bing.com/search?q=raymond+chen+the+implementation+of+迭代器

接下来,阅读乔恩·斯基特的书中关于这个主题的章节:

http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx

如果您仍然感兴趣,请阅读我的系列文章,了解涉及此功能的设计因素:

http://blogs.msdn.com/b/ericlippet/archive/tags/iterators/


回到过去,在我们使用yield运算符之前,我们常常编写实现IEnumerator的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class PowerEnumerator : IEnumerator<int>
{
  private int _number;
  private int _exponent;
  private int _current = 1;

  public PowerEnumerator(int number, int exponent)
  {
    _number = number;
    _exponent = exponent;
  }

  public bool MoveNext()
  {
    _current *= number;
    return _exponent-- > 0;
  }

  public int Current
  {
    get
    {
      if (_exponent < 0) throw new InvalidOperationException();
      return _current;
    }
  }
}

或者类似的。我告诉你,这不好玩。


  • 让.NET Reflector对其进行反编译。这是一个通用的解决方案(实际上是一个状态机),但是相当复杂,如果我记得正确的话,超过20行代码。
  • 懒惰的这就是为什么yield可以相当高效的原因。

  • 这将是IEnumerable的自定义实现,而不是依赖于现有的实现,如List
  • 懒洋洋地
  • 此处提供更多信息。