Ser*_*nov 6 c# ienumerable ienumerator
我当前的应用程序中有命令层次结构.
public interface ICommand
{
void Execute();
}
Run Code Online (Sandbox Code Playgroud)
所以,有些命令是有状态的,有些则不是.
我需要在循环方式中枚举IEnumerable,以便在命令执行期间执行某些命令.
public class GetNumberCommand : ICommand
{
public GetNumberCommand()
{
List<int> numbers = new List<int>
{
1, 2, 3
};
}
public void Execute()
{
// Circular iteration here.
// 1 => 2 => 3 => 1 => 2 => 3 => ...
}
public void Stop()
{
// Log current value. (2 for example)
}
}
Run Code Online (Sandbox Code Playgroud)
Execute 被不时调用,因此有必要存储迭代状态.
如何实现循环枚举?
我找到了两个解决方案:
使用IEnumerator<T>界面.看起来像:
if (!_enumerator.MoveNext())
{
_enumerator.Reset();
_enumerator.MoveNext();
}
Run Code Online (Sandbox Code Playgroud)使用循环IEnumerable<T>(yield永远相同的顺序):
实现循环迭代器.
也许还有更多方法可以实现它.你会建议使用什么?为什么?
而不是处理 IEnumerator 接口,
foreach (var x in GetSomething())
{
if (someCondition) break;
}
public IEnumerable<int> GetSomething()
{
List<int> list = new List<int>() { 1, 2, 3 };
int index=0;
while (true)
yield return list[index++ % list.Count];
}
Run Code Online (Sandbox Code Playgroud)
这是我刚刚作为扩展实现的一个。
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace DroopyExtensions
{
public static class CircularEnumaratorExtensionMethod
{
public static IEnumerator<T> GetCircularEnumerator<T>(this IEnumerable<T> t)
{
return new CircularEnumarator<T>(t.GetEnumerator());
}
private class CircularEnumarator<T> : IEnumerator<T>
{
private readonly IEnumerator _wrapedEnumerator;
public CircularEnumarator(IEnumerator wrapedEnumerator)
{
this._wrapedEnumerator = wrapedEnumerator;
}
public object Current => _wrapedEnumerator.Current;
T IEnumerator<T>.Current => (T)Current;
public void Dispose()
{
}
public bool MoveNext()
{
if (!_wrapedEnumerator.MoveNext())
{
_wrapedEnumerator.Reset();
return _wrapedEnumerator.MoveNext();
}
return true;
}
public void Reset()
{
_wrapedEnumerator.Reset();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
要使用它,您所要做的就是
using DroopyExtensions;
class Program
{
static void Main(string[] args)
{
var data = new List<string>() {"One", "Two", "Tree"};
var dataEnumerator = data.GetCircularEnumerator();
while(dataEnumerator.MoveNext())
{
Console.WriteLine(dataEnumerator.Current);
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用此扩展方法:
public static IEnumerable<T> Cyclic<T>(this IEnumerable<T> @this)
{
while (true)
foreach (var x in @this)
yield return x;
}
Run Code Online (Sandbox Code Playgroud)
以这种方式:
public class GetNumberCommand : ICommand
{
private readonly IEnumerator<int> _commandState = new[] { 1, 2, 3 }.Cyclic().GetEnumerator();
public void Execute()
{
_commandState.MoveNext();
var state = _commandState.Current;
//
// Do stuff with state
//
}
public void Stop()
{
var state = _commandState.Current;
// Log state value. (2 for example)
}
}
Run Code Online (Sandbox Code Playgroud)