C#: How to translate the Yield Keyword
Sample:
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);
}
}
}
If the yield operator is eagerly evaluated here is my guess:
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;
}
I have no clue what it might look like if the yield operator is lazily evaluated.
Update: Reflector gives this:
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;
}
Back in the good old days, before we had the yield operator, we used to write classes which implemented IEnumerator.
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;
}
}
}
Or something like that. It wasn't fun, let me tell you.
First off, yield is not an operator. yield return and yield break are statements.
There are plenty of articles available on how the compiler implements iterator blocks. Start by reading the C# specification section on iterator blocks; it gives some suggestions for how an implementer of C# might want to go about it.
Next read Raymond Chen's series "The implementation of iterators in C# and its consequences"
http://www.bing.com/search?q=raymond+chen+the+implementation+of+iterators
Next, read Jon Skeet's book chapter on the subject:
http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx
If after all that you are still interested then read my series on the design factors that went into this feature:
http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/
yield
can be quite efficient. 上一篇: 收益声明对程序流的影响
下一篇: C#:如何翻译收益关键字