2012-05-22 28 views
6

Existe la jerarquía de comandos en mi aplicación actual.C#: enumeración circular de IEnumerable

public interface ICommand 
{ 
    void Execute(); 
} 

Por lo tanto, algunos comandos son con estado, otros no.

Necesito enumerar IEnumerable de forma circular para implementar algunos comandos durante la ejecución del comando.

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 se llama de vez en cuando, por lo que es necesario para almacenar el estado de iteración.

¿Cómo implementar esa enumeración circular?

he encontrado dos soluciones:

  1. Mediante la interfaz de IEnumerator<T>. Parece que :

    if (!_enumerator.MoveNext()) 
    { 
        _enumerator.Reset(); 
        _enumerator.MoveNext(); 
    } 
    
  2. Usando la circular IEnumerable<T> (yield siempre la misma secuencia): Implementing A Circular Iterator.

Quizás haya más formas de lograrlo. ¿Qué recomendarías usar y por qué?

Respuesta

1
while (!stop) 
{ 
    foreach (var i in numbers) 
    { 
    // do something 
    } 
} 
+0

En mi caso, se ejecuta 'Execute' de vez en cuando, por lo que es necesario almacenar el estado de iteración. –

4

lugar de tratar con la interfaz 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]; 
} 
+1

Creo que obtendrás un desbordamiento en el índice muy pronto si te gusta eso –

+0

En mi caso, se ejecuta 'Execute' de vez en cuando, por lo que es necesario almacenar el estado de la iteración. –

+0

ver mi solución al final. puede almacenar el índice en la colección y pasarlo al iterador –

0

Creo que, de la manera más cómoda bebe será implementar colección personalizada con empadronador costumbre y encapsular lógica circular en ella.

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> {} 

algo como esto ...

-1

Puede escribir un enumerable circular sin retornos de rendimiento.

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