このことを考慮:
List<MyClass> obj_list = get_the_list();
foreach( MyClass obj in obj_list )
{
obj.property = 42;
}
「obj」はリスト内の対応するオブジェクトへの参照であるため、プロパティを変更すると、変更はどこかに構築されたオブジェクトインスタンスに保持されますか?
はい、obj
はコレクション内の現在のオブジェクトへの参照です(MyClass
が実際にはクラスであると仮定します)。参照を介してプロパティを変更すると、予想どおりにオブジェクトが変更されます。
ただし、変数obj
自体は反復変数なので変更できないことに注意してください。実行しようとすると、コンパイルエラーが発生します。つまり、nullにすることはできず、値の型を反復している場合は、値を変更するため、メンバーを変更することはできません。
C#言語仕様の状態(8.8.4)
「反復変数は、埋め込みステートメントに及ぶスコープを持つ読み取り専用ローカル変数に対応しています。」
はい、ジェネリック型をListからIEnumerableに変更するまで。
ここで2つの異なる質問をしました。順番にそれらを取りましょう。
参照によるC++ forループと同じ意味で意味する場合、いいえ。 C#には、C++と同じ意味でのローカル変数参照がないため、このタイプの反復をサポートしていません。
MyClassが参照型であると仮定すると、答えはイエスです。クラスは.Netの参照型であるため、反復変数はコピーではなく1つの変数への参照です。これは、値の型には当てはまりません。
さて、varコレクションを反復処理したときに、foreachループで変更が更新されなかったことがわかりました。
var players = this.GetAllPlayers();
foreach (Player player in players)
{
player.Position = 1;
}
VarをListに変更すると、動作し始めました。
このインスタンスでできます(List<T>
)ただし、ジェネリックIEnumerable<T>
その後、その実装に依存するようになります。
それでもList<T>
またはT[]
たとえば、すべてが期待どおりに機能します。大きな問題は、IEnumerable<T>
yieldを使用して構築されました。この場合、繰り返し内でT
のプロパティを変更することはできず、同じIEnumerable<T>
もう一度。
これは、構造体でない限り当てはまります。
おそらく、バージョンC#7.3では、列挙子のCurrentプロパティが参照Typeを返すことを条件に、参照によって値を変更できることが興味深いでしょう。以下が有効です(MSドキュメントからの逐語的なコピー):
Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
item = num++;
}
この新機能の詳細については、 C#foreachステートメント| Microsoft Docs をご覧ください。
「参照による反復」の意味を正確に理解せずに、具体的に「はい」または「いいえ」と答えることはできませんが、表面下で起こっていることは、.netフレームワークが「列挙」クラスを構築していると言うことができますクライアントコードがforeachを呼び出しているたびに、foreachの有効期間中、反復されるコレクションへの参照ポインターを保持し、foreachが反復するたびに、1つのアイテムを「配信」し、ポインターまたは参照を「インクリメント」します次のアイテムの列挙子...
これは、繰り返し処理するコレクション内のアイテムが値型か参照型かに関係なく発生します。
objはList内のアイテムへの参照です。したがって、値を変更しても保持されます。 今、あなたが心配しなければならないのは、get_the_list();がListのディープコピーを作成するか、同じインスタンスを返すかどうかです
はい、それが、foreachステートメントのコンテキストで列挙可能なオブジェクトを変更できない理由でもあります。