web-dev-qa-db-ja.com

foreachループなしでIEnumerableを使用する

ここで簡単なものを見逃す必要があります。

次のコードを取得します。

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

私はこれを呼び出すことができます:

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

ForeachループなしでgetIntメソッドを使用するにはどうすればよいですか:

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

ありがとう。

[〜#〜] edits [〜#〜]

なぜ私はこれが欲しいのかと思っている人のために。私は2つのことを繰り返しています:

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

Enumerator メソッドを使用して、GetEnumeratorへの参照を取得できます。次に、 MoveNext() を使用できます。次のメソッドに進み、Currentプロパティを使用して要素にアクセスします。

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

私のアドバイス:列挙子をいじってはいけません。問題をシーケンスに対する一連の操作として特徴付けます。これらの操作を表現するコードを記述します。シーケンス演算子に列挙子の管理を任せてください。

それで、私がこれをまっすぐに持っているかどうか見てみましょう。 2つのシーケンスがあります。 {2、3、5、7、12}と{"frog"、 "toad"}としましょう。実行する論理演算は、「最初のシーケンスを通過します。3で割り切れる数を見つけるたびに、2番目のシーケンスの次の項目を取得します。結果の(数、両生類)ペアで何かを行います。」

簡単にできました。最初に、最初のシーケンスをフィルタリングします。

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

次に、フィルタリングされたシーケンスを2番目のシーケンスで圧縮します。

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

そして今、あなたはzip形式のシーケンスを反復処理し、ペアで何でもしたいことができます:

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

簡単で、列挙子をいじることはありません。

31
Eric Lippert

これはどう?

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

forループの使用:

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

受け入れられた答えは正しいですが、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;
}
0
Doug

インスタンスが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();
    }
}
0
Groo