Использование IEnumerable без цикла foreach

Я должен пропустить что-то простое здесь.

Возьмите следующий код:

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

Я могу назвать это с:

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

Как я могу использовать метод getInt без цикла foreach:

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

Благодарю.

редактирует

Для тех, кто интересуется, почему я хочу этого. Я повторяю две вещи:

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

6 ответов

Решение

Вы можете получить ссылку на Enumerator, с использованием GetEnumerator метод, то вы можете использовать MoveNext() метод двигаться дальше, и использовать Current свойство для доступа к вашим элементам:

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

Мой совет: не связывайтесь с счетчиками вообще. Охарактеризуйте свою проблему как последовательность операций над последовательностями. Напишите код для выражения этих операций. Пусть операторы последовательности позаботятся об управлении перечислителями.

Итак, давайте посмотрим, понял ли я это прямо. У вас есть две последовательности. Допустим, { 2, 3, 5, 7, 12 } и { "лягушка", "жаба" }. Логическая операция, которую вы хотите выполнить, это сказать: "пройти через первую последовательность. Каждый раз, когда вы найдете число, делимое на три, получите следующий элемент во второй последовательности. Сделайте что-нибудь с полученной парой (число, амфибия)".

Легко сделано. Сначала отфильтруйте первую последовательность:

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

Затем, отфильтруйте отфильтрованную последовательность со второй последовательностью:

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

И теперь вы можете перебирать заархивированную последовательность и делать с парами все, что захотите:

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

Легко peasy, не возиться с счетчиками.

Как насчет этого?

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

Использование для цикла:

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

Хотя принятые ответы верны, обратите внимание, что IEnumerator.Current не определен перед первым вызовом MoveNext().

Если вы перебираете вторичный массив, вам нужно что-то вроде:

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

Важно отметить, что долг foreach Цикл должен располагать перечислитель, если экземпляр реализует IDisposable, Другими словами, foreach следует заменить на что-то вроде:

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

Образец,

public static void SampleIteratorNext()
{
    var beauty = BeautifulLadies().GetEnumerator();

    Console.WriteLine($"Friday with {Next(beauty)} ...");
    Console.WriteLine($"Saturday with {Next(beauty)} ...");
    Console.WriteLine($"Tusday with {Next(beauty)} ...");
}

public static IEnumerable<string> BeautifulLadies()
{
    yield return "Scarlett";
    yield return "Alexandra";
    yield return "Alisson";
}

// emulate next() in python
public static T Next<T>(IEnumerator<T> iterator)
{
    iterator.MoveNext();
    return iterator.Current;
}
Другие вопросы по тегам