web-dev-qa-db-ja.com

foreachループはC#でどのように機能しますか?

どのタイプのクラスがforeachループを使用できますか?

83
user48616

実際、厳密に言えば、foreachを使用するために必要なのは、GetEnumerator()メソッドと_? Current {get;}_プロパティで何かを返すpublic bool MoveNext()メソッドだけです。 。ただし、これの最もcommonの意味は「IEnumerable/_IEnumerable<T>_を実装し、IEnumerator/_IEnumerator<T>_を返すものです。

暗黙的に、これにはICollection/_ICollection<T>_を実装するものがすべて含まれます。たとえば、_Collection<T>_、_List<T>_、配列(_T[]_)などです。 「データの収集」は通常、foreachをサポートします。

最初のポイントを証明するために、以下がうまく機能します:

_using System;
class Foo {
    public int Current { get; private set; }
    private int step;
    public bool MoveNext() {
        if (step >= 5) return false;
        Current = step++;
        return true;
    }
}
class Bar {
    public Foo GetEnumerator() { return new Foo(); }
}
static class Program {
    static void Main() {
        Bar bar = new Bar();
        foreach (int item in bar) {
            Console.WriteLine(item);
        }
    }
}
_

どのように機能しますか?

foreach(int i in obj) {...}のようなforeachループは、次と同等です:

_var tmp = obj.GetEnumerator();
int i; // up to C# 4.0
while(tmp.MoveNext()) {
    int i; // C# 5.0
    i = tmp.Current;
    {...} // your code
}
_

ただし、バリエーションがあります。たとえば、列挙子(tmp)がIDisposableをサポートしている場合、それも使用されます(usingと同様)。

違いに注意してください宣言の配置で "_int i_"inside(C#5.0)vs.outside(C#4.0まで)ループ。コードブロック内の匿名メソッド/ラムダでiを使用する場合は重要です。しかし、それは別の話です;-p

158
Marc Gravell

[〜#〜] msdn [〜#〜] から:

foreachステートメントは、配列またはオブジェクトコレクションの各要素に対して埋め込みステートメントのグループを繰り返します。 foreachステートメントは、コレクションを反復して目的の情報を取得するために使用されますが、予期しない副作用を避けるためにコレクションの内容を変更するために使用しないでください。 (エンファシス鉱山)

したがって、配列がある場合は、次のようにforeachステートメントを使用して配列を反復処理できます。

 int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 };
    foreach (int i in fibarray)
    {
        System.Console.WriteLine(i);
    }

次のように、List<T>コレクションを反復処理するために使用することもできます。

List<string> list = new List<string>();

foreach (string item in list)
{
    Console.WriteLine(item);
}
6
George Stocker

ブログの投稿ダック表記によると、ダックタイピングが使用されます。

4
tuinstoel

ここにドキュメントがあります: メイン記事配列を使用コレクションオブジェクトを使用

「コレクション要素の型は、識別子の型に変換可能でなければならない」ことに注意することが重要です。これは、コンパイル時にチェックできないことがあり、インスタンスタイプが参照タイプに割り当てられない場合、ランタイム例外を生成する可能性があります。

オレンジなど、フルーツバスケットにアップル以外のものがある場合、これによりランタイム例外が生成されます。

List<Fruit> fruitBasket = new List<Fruit>() { new Apple(), new Orange() };
foreach(Apple a in fruitBasket)

これは、 Enumerable.OfType を使用して、Appleのみにリストを安全にフィルタリングします

foreach(Apple a in fruitBasket.OfType<Apple>() )
2
Amy B