10

我当前的应用程序中有命令层次结构。

public interface ICommand
{
    void Execute();
}

因此,有些命令是有状态的,有些则不是。

我需要在命令执行期间以循环方式枚举 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)
    }
}

Execute时不时调用,所以需要存储迭代状态。

如何实现该循环枚举?

我找到了两个解决方案:

  1. 使用IEnumerator<T>界面。看起来像:

     if (!_enumerator.MoveNext())
     {
         _enumerator.Reset();
         _enumerator.MoveNext();
     }
    
  2. 使用循环IEnumerable<T>yield永远相同的序列):“实现循环迭代器”-HonestIllusion.Com

也许,有更多的方法来实现它。
你会推荐使用什么,为什么?

4

6 回答 6

6

而不是处理 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];
}
于 2012-05-22T06:03:59.530 回答
4

这是我刚刚作为扩展实现的一个。

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();
            }
        }
    }   
} 

要使用它,您所要做的就是

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);
        }
    }
}
于 2019-02-15T16:23:41.073 回答
1
while (!stop)
{
   foreach (var i in numbers)
   {
     // do something
   }
}
于 2012-05-22T06:00:52.847 回答
1

您可以使用此扩展方法:

public static IEnumerable<T> Cyclic<T>(this IEnumerable<T> @this)
{
    while (true)
        foreach (var x in @this)
            yield return x;
}

以这种方式:

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)
    }
}
于 2021-10-13T10:24:33.447 回答
-1

我认为,最舒适的方法是使用自定义枚举器实现自定义集合并在其中封装循环逻辑。

class Collection<T> : IEnumerable<T>
{
  bool circle;

  List<T> collection = new List<T>();

  public IEnumerable<T> IEnumerable<T>.GetEnumerator()
  {
     if(circle) return new CustomEnumerator<T>(this);
     return circle.GetEnumerator();
  }
}

class CustomEnumerator : Enumerator<T> {}

像这样的东西......

于 2012-05-22T06:08:11.560 回答
-1

您可以编写一个没有收益返回的循环枚举。

  public class CircularEnumerable<T> : IEnumerable<T>
  {
    public CircularEnumerable (IEnumerable<T> sequence)
    {
      InfiniteLoop = sequence.Concat (this);
    }

    private readonly IEnumerable<T> InfiniteLoop;

    public IEnumerator<T> GetEnumerator ()
    {
      return InfiniteLoop.GetEnumerator ();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
    {
      return InfiniteLoop.GetEnumerator ();
    }
  }

public class GetNumberCommand : ICommand
{
    public GetNumberCommand()
    {
        List<int> numbers = new List<int>
            {
                1, 2, 3
            };
        infiniteLoopOnNumbers = new CircularEnumerable<int>(numbers).GetEnumerator();
    }

    IEnumerator<int> infiniteLoopOnNumbers; 

    public void Execute()
    {
        infiniteLoopOnNumbers.MoveNext();
    }

    public void Stop()
    {
        int value = infiniteLoopOnNumbers.Current;
    }
}
于 2013-04-13T20:02:22.543 回答