Jor*_*rge 1 .net c# ienumerator design-patterns
如何在GetEnumerator不使用yield关键字的情况下重写方法?方法代码:
public IEnumerator<int> GetEnumerator()
{
yield return 1;
Console.WriteLine("1");
yield return 2;
}
Run Code Online (Sandbox Code Playgroud)
我只知道如何手动实现它.
实际上,该yield语句是一种语法糖,它使编译器实际生成一个实现IEnumerator<T>接口的类,并使用该yield语句将该方法的主体重写为状态机.
每个状态都与最终生成序列中下一个元素的代码的一部分相关联.这嵌入在MoveNext()方法中.状态机可以表示所有必要的构造(序列,选择,迭代),因此所有C#代码(意味着方法中的语句)都可以像这样重写.这是潜在的"魔力" yield.
在您的特定情况下,这种重写到状态机和相应的完整实现IEnumerator<T>(及其继承IEnumerator(非泛型)和IDisposable接口)将如下所示:
public class CustomEnumerator : IEnumerator<int>
{
public int Current { get; private set; }
object IEnumerator.Current => this.Current;
// internal 'position' in the sequence, i.e. the current state of the state machine
private int position = 0;
public bool MoveNext()
{
// advance to next state
// (works for linear algorithms; an alternative is to select the next state at the end of processing the current state)
position++;
// perform the code associated with the current state and produce an element
switch (position)
{
// state 1: line 'yield return 1;'
case 1:
Current = 1;
return true;
// state 2: lines 'Console.WriteLine("1");' and 'yield return 2;'
case 2:
Console.WriteLine("1"); // see also note at the end of this answer
Current = 2;
return true;
// there are no other states in this state machine
default:
return false;
}
}
public void Reset()
{
position = 0;
}
public void Dispose()
{
// nothing to do here
}
}
Run Code Online (Sandbox Code Playgroud)
每次调用MoveNext(),即在foreach语句的每次迭代内部发生的事情,都会导致执行一部分代码 - 直到生成序列中的下一个元素.
为了使这个实现可用,相应的IEnumerable<T>实现是必要的,这是非常简单的:
public class CustomEnumerable : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new CustomEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Run Code Online (Sandbox Code Playgroud)
然后以下两个foreach循环将产生完全相同的结果:
void Main()
{
// custom implementation of IEnumerator<T>
foreach (int i in new CustomEnumerable())
{
Console.WriteLine(i);
}
// your original implementation—will produce same results
// note: I assume someObject implements IEnumerable<T> and hence your GetEnumerator() method
foreach (int i in someObject)
{
Console.WriteLine(i);
}
}
Run Code Online (Sandbox Code Playgroud)
注意:在您的GetEnumerator()代码中,调用Console.WriteLine("1");是在枚举器返回之后1(并且调用者处理它),因此看起来有点奇怪.
| 归档时间: |
|
| 查看次数: |
374 次 |
| 最近记录: |