リンク内容
上記のサイトに書いてあるようにc#ではforループの中で構造体のlistの値を変更できません
なぜできないのか理由を教えてください
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
参照型でないためです。
C#
1struct SampleData 2{ 3 public bool Status; 4}
C#
1var sampleData = new List<SampleData>(); 2sampleData.Add(new SampleData()); 3for (int i = 0; i < sampleData.Count; i++) 4{ 5 sampleData[i].Status = true; 6}
上記の時、sampleData[i] は sampleData の i + 1 番目の要素のコピーを返します。コピーのメンバを変更してもオリジナルには影響しません。そのため、コピーのフィールドを変更しただけでこの値を使用しなかった場合、紛らわしいのでこれをエラーにします。
エラーにならなかった場合、一見正しいように見えるので非常に見つけにくいバグになりかねません。
次のようにして確かめてみてください。sampleData[i].Status は false で初期化されます。したがって、最初の Debug.WriteLine は false を出力します。しかし、次の Debug.WriteLine は true を出力します。
C#
1var sampleData = new List<SampleData>(); 2sampleData.Add(new SampleData()); 3for (int i = 0; i < sampleData.Count; i++) 4{ 5 var datum = sampleData[i]; 6 datum.Status = true; 7 Debug.WriteLine(sampleData[i].Status); 8 Debug.WriteLine(datum.Status); 9}
つまり、sampleData[i].Status = true;
とした時、sampleData から i + 1 番目の要素のコピーが取り出され、その Status フィールドが true に変更されますが、取り出されたコピーはどこからも参照されることなく消えていくという意味のないコードになります。これをエラーとしてユーザーに明示的に注意喚起しているのです。
投稿2017/05/10 14:38
編集2017/05/10 15:11総合スコア28662
0
参照型だからではなくて List<T>
のインデクサは 値を返すからでは? 配列は ref 戻り値を返せるので直接変更できます。
cs
1using System; 2using System.Collections.Generic; 3using System.Runtime.InteropServices; 4 5{ 6 ValueStruct[] array = [1,2,3]; 7 Console.WriteLine(string.Join(", ", array)); 8 array[0].Num = 10; 9 Console.WriteLine(string.Join(", ", array)); 10 // 配列のインデクサアクセスは ref 戻り値なので 参照を返す 11 ref var l = ref array[1]; 12 l.Num = 20; 13 Console.WriteLine(string.Join(", ", array)); 14} 15{ 16 List<ValueStruct> list = [1,2,3]; 17 Console.WriteLine(string.Join(", ", list)); 18 // // エラーになるので代入できない 19 // list[0].Num = 10; 20 // Console.WriteLine($"[{string.Join(", ", list)}"); 21 22 // 内部配列を Span<T> として取得する 23 var span = CollectionsMarshal.AsSpan(list); 24 span[1].Num = 10; 25 Console.WriteLine(string.Join(", ", list)); 26 27 // Span<T> のインデクサアクセスは ref 戻り値なので 参照を返す 28 ref var s = ref span[2]; 29 s.Num = 10; 30 Console.WriteLine(string.Join(", ", list)); 31} 32 33 34struct ValueStruct 35{ 36 public int Num {get;set;} 37 public ValueStruct(int Num) => this.Num = Num; 38 public override string ToString() => $"{nameof(ValueStruct)}{{{nameof(Num)} = {Num}}}"; 39 public static implicit operator ValueStruct(int num) => new(num); 40}
ValueStruct{Num = 1}, ValueStruct{Num = 2}, ValueStruct{Num = 3} ValueStruct{Num = 10}, ValueStruct{Num = 2}, ValueStruct{Num = 3} ValueStruct{Num = 10}, ValueStruct{Num = 20}, ValueStruct{Num = 3} ValueStruct{Num = 1}, ValueStruct{Num = 2}, ValueStruct{Num = 3} ValueStruct{Num = 1}, ValueStruct{Num = 10}, ValueStruct{Num = 3} ValueStruct{Num = 1}, ValueStruct{Num = 10}, ValueStruct{Num = 10}
投稿2024/02/26 07:18
総合スコア453
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/10 15:12