C#: How to translate the Yield Keyword
百万千克1如果没有yield关键字,msdn示例会是什么样子?如果你表现出色,你可以用任何例子。我只想知道引擎盖下面发生了什么。百万千克1百万千克1收益率运算符的评估是积极的还是迟缓的?百万千克1
让.NET Reflector对其进行反编译。这是一个通用的解决方案(实际上是一个状态机),但是相当复杂,如果我记得正确的话,超过20行代码。
懒惰的这就是为什么yield 可以相当高效的原因。
这将是IEnumerable 的自定义实现,而不是依赖于现有的实现,如List 。
懒洋洋地
样品:
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; } } } |
或者类似的。我告诉你,这不好玩。
此处提供更多信息。