web-dev-qa-db-fra.com

Utiliser IEnumerable sans boucle foreach

Il me manque quelque chose de simple ici.

Prenez le code suivant:

public IEnumerable<int> getInt(){
  for(int i = 0; i < 10; i++){
   yield return i;
  }
}

Je peux appeler ça avec:

foreach (int j in obj.getInt()){
  //do something with j
}

Comment puis-je utiliser la méthode getInt sans la boucle foreach:

IEnumerable<int> iter = obj.getInt();
// do something with iter ??

Merci.

ÉDITE

Pour ceux qui se demandent pourquoi je voudrais cela. Je répète deux choses:

IEnumerator<int> iter = obj.getInt().GetEnumerator();
foreach(object x in xs){
  if (x.someCondition) continue;
  iter.MoveNext();
  int n = iter.current();
  x.someProp = n;
  etc...
}
35
Mark

Vous pouvez obtenir une référence à la Enumerator, en utilisant la méthode GetEnumerator , puis vous pouvez utiliser la MoveNext() pour continuer et utilisez la propriété Current pour accéder à vos éléments:

var enumerator = getInt().GetEnumerator();
while(enumerator.MoveNext())
{
    int n = enumerator.Current;
    Console.WriteLine(n);
}
59
CMS

Mon conseil: ne plaisante pas avec les enquêteurs. Caractérisez votre problème comme une série d'opérations sur des séquences. Écrivez du code pour exprimer ces opérations. Laissez les opérateurs de séquence se charger de gérer les énumérateurs.

Voyons donc si j'ai bien compris. Vous avez deux séquences. Disons {2, 3, 5, 7, 12} et {"grenouille", "crapaud"}. L'opération logique que vous souhaitez effectuer est, par exemple, "passer par la première séquence. Chaque fois que vous trouvez un nombre divisible par trois, obtenez l'élément suivant dans la deuxième séquence. Faites quelque chose avec la paire résultante (nombre, amphibiens)".

Facile à faire. Tout d'abord, filtrez la première séquence:

var filtered = firstSequence.Where(x=>x%3 == 0);

Ensuite, fermez la séquence filtrée avec la deuxième séquence:

var zipped = filtered.Zip(
             secondSequence, 
             (y, z)=> new {Number = x, Amphibian = y});

Et maintenant, vous pouvez parcourir la séquence zippée et faire ce que vous voulez avec les paires:

foreach(var pair in zipped)
    Console.WriteLine("{0} : {1}", pair.Number, pair.Amphibian);

Peasy facile, ne plaisante pas avec les enquêteurs.

31
Eric Lippert

Que dis-tu de ça?

IEnumerator<int> iter = obj.getInt();
using(iter) {
    while(iter.MoveNext()) {
        DoSomethingWith(iter.Current)
    }
}
4
zildjohn01

utilisation de la boucle:

for (var enumerator = getInt().GetEnumerator(); enumerator.MoveNext(); )
{
    Console.WriteLine(enumerator.Current);
}
2
sanjuro

Bien que les réponses acceptées soient correctes, notez que IEnumerator.Current n'est pas défini avant le premier appel à MoveNext ().

Si vous parcourez un tableau secondaire, vous voudrez quelque chose comme:

IEnumerable<Foo> Foo() { ... }

int AssignValues(List<TakesFoo> data) {
  var count = 0;
  var foo = Foo().GetEnumerator();

  // Step into the first element of the array;
  // doing this does not discard a value from the IEnumerator
  if (foo.MoveNext()) { 
    foreach (var x in data) {
      x.SetFoo(foo.Current);
      count += 1;
      if (!foo.MoveNext()) { 
        break;
      }
   }

   // Return count of assigned values
   return count;
}
0
Doug

Il est important de mentionner que le devoir de la boucle foreach est de disposer l'énumérateur si l'instance implémente IDisposable. En d'autres termes, foreach doit être remplacé par quelque chose comme:

var enumerator = enumerable.GetEnumerator();

try
{
    while (enumerator.MoveNext())
    {
        var item = enumerator.Current;
        // do stuff
    }
}
finally
{
    var disposable = enumerator as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}
0
Groo