2012-03-14 1 views
0
   var names = new[] { 
          new { Name = "John", Age = 44 }, 
          new { Name = "Diana", Age = 45 }, 
          new { Name = "James", Age = 17 }, 
          new { Name = "Francesca", Age = 15} 
          }; 

      for (int i = 0; i < names.Length; i++) 
      { 
       names[i].Age = 23; //-------->Error 
       names[i] = new { Name = "XYX", Age = 26 }; //----->Works fine 
      } 

      foreach(var name in names) 
      { 
       name.Age = 1; //-------->Error 
       name = new { Name = "ABC", Age = 25 }; //-------->Error 
      } 

ここでは2つの質問があります。 1.なぜ反復変数のany属性を変更できなかったのですか?
2. forループの反復変数にのみ新しいオブジェクトを割り当てることができました。 foreachループではありません。どうして?foreachループで反復変数を変更できないのはなぜですか?

答えて

9

質問1:なぜ反復変数の任意の属性を変更できなかったのですか? Anonymous Typesのドキュメントから

匿名型は、読み取り専用プロパティ

をあなたは、あなたの中のプロパティの値を変更することはできませんのセットをカプセル化するための便利な方法を提供します匿名タイプなので、

name.Age = 1; 
// and 
names[i].Age = 1; 

は等しく無効です。


質問2.私は、forループで反復変数に新しいオブジェクトを割り当てることができました。 foreachループではありません。どうして?ドキュメントから

IEnumerable上:

列挙子はコレクションが変わらない限り有効です。

バッキングリストを変更すると、イテレータが無効になります。たとえば、イテレータがAgeフィールドに基づいて特定の順序でアイテムを返した場合に起こることを考えてください。

+0

注:これは質問1の回答です。 – Matthias

+0

ソートの問題について言及するまで、私はあなたと意見の相違がありました。今分かります。どうもありがとう! –

7

なぜ私は反復変数の任意の属性を変更できませんでした。

あなたはC#で常に読み取り専用のプロパティを持つ匿名型を使用しています。 (彼らは、デフォルトでは読み取り/書き込みしているが、Key修飾子を読み取り専用に行うことができるVBで。)

C#4の仕様から、セクション7.6.10.6:匿名オブジェクト初期化子を宣言

匿名型を返し、その型のインスタンスを返します。匿名型は、objectから直接継承する名前のないクラス型です。匿名型のメンバは、型のインスタンスを作成するために使用される匿名オブジェクト初期化子から推測された読み込み専用プロパティのシーケンスです。あなたの2番目の質問については

...

私はforループで反復変数に新しいオブジェクトを割り当てることができました。 foreachループではありません。どうして?

言語仕様は、このように定義しています。特に、に変更されても、その言語仕様では配列の場合はが機能しない限り、配列は変更されません。一般に、foreachは、IEnumerable/IEnumerator(またはそのように見えるメンバー)を使用し、シーケンスの「読み取り」ビューのみを提供します。

反復変数は、埋め込みステートメントにわたって延在範囲と読み取り専用のローカル変数に対応する:C#4仕様のセクション8.8.4から

(重要なのは、1つの読み取り専用変数ですが、その値は反復の間で変わります)。C#5では、これは効果的に各繰り返しで「新しい」変数に変更されます。変数はラムダ式のようなもので捕捉されます)。

+0

特に、変数を変更することができたとしても、配列を変更することはできません。この変数は元のオブジェクトのコピーを保持していますか? –

+1

@vaibhav:いいえ、元のオブジェクトに*参照*のコピーを保持します。配列には参照のみが保持されます。配列の値を変更する場合は、*配列の内容を変更する必要があります*。配列内の参照の* copy *である変数を変更するだけでは何もしません。 –

+0

names [i] = new object、このステートメントでは、元のオブジェクトを変更していますが、コピーはコピーしていません。 –

0

質問2):「うまくいく」ケースでは、反復変数を変更していません。その場合、反復変数はiです。あなたがしているのは、配列のある要素を新しい要素に置き換えることです。これは常に動作します。

0

foreachは列挙子を使用するため、列挙子は基になるコレクションを変更できませんが、コレクション内のオブジェクトによって参照されるオブジェクトはすべて変更できます。ここでは、Value型とReference型のセマンティクスが機能します。

参照型、つまりクラスでは、すべてのコレクションはオブジェクトへの参照です。そのように、実際にはオブジェクトのメンバーのどれにも触れることはありません。オブジェクトの変更はコレクションには反映されません。

一方、値型は、その構造全体をコレクションに格納します。コレクションを変更せずに列挙子を無効にすることなくメンバーに触れることはできません。

さらに、列挙子は、コレクション内の値のコピーを返します。 ref-typeでは、これは何も意味しません。参照のコピーは同じ参照となり、変更がスコープ外に広がった状態で参照されたオブジェクトを変更することができます。一方、値型では、あなたが得るのはオブジェクトのコピーであり、そのコピー上の変更は決して伝播しないということです。

関連する問題