2012-07-10 16 views
10
私は今日、次の行動を観察した偉大びっくりして

:クラスプロパティの変更.Current

class Foo 
{ 
    prop int FooNumber { get; set; } 
} 

と、このコードが与えられ

IEnumerable<Foo> foos = Enumerable.Range(0,3).Select(new Foo()); 

foreach (var foo in foos) 
    foo.Bar = 5; 

foreach (var foo in foos) 
    Console.Write(foo.Bar); // Writes 000 

new List<Foo>{ new Foo(), new Foo(), new Foo() }からfoosを初期化すると、ループの書き込みを行いながら " 555 "。

私の質問:なぜこれが起こり、.ToList()を使用してこれを回避する方法があるのですか(ここではコメントは必要ありません)。

+4

ReSharperが「可能な複数の列挙」と呼べる素晴らしい世界へようこそ。列挙型はコレクションではありません**。列挙型がコレクション上にあり、その下にある列挙型を変更できることは、副作用です。 –

答えて

20

これは、foosが列挙されるたびに動的に生成されるために発生します。最初の反復処理では、反復処理が終了した後にオブジェクトによって参照されなくなったオブジェクトのプロパティ値を設定します。 2番目の反復は、デフォルトのプロパティ値を持つ新しく構築されたオブジェクトで機能します。 「永続的な」オブジェクトのリストにfoosを初期化

は、同じ理由で.ToList()を使用しないよう(「固定」リストが構築され、二回以上繰り返され、オリジナルの動的生成IEnumerableは一回だけしか巡回さ)、物事を変更します。一般的に私は複数回動的に生成シーケンスを反復処理するのが通例ではないのでコメントを必要とそれは(私は多くのコード分析ツールは、このに対して警告信じていることを感じていない:あなたがここに.ToList()を使用する必要があることを確立した

)しかし、忘れないでください。

+0

それは、ありがとう、それを説明します。私は最初の列挙の後に結果がどこかに保存されるという誤った印象のもとにいました。 – Jens

3

何が起こっているのは明らかです:列挙するたびに、新しいFooオブジェクトをインスタンス化しています。

あなたが保存するプロパティ値(Foo.Barを)したい場合は、あなたがフーのどこか、およびToListメソッド()を維持する必要があるとしているが、これを行うための簡単な方法です。

関連する問題