旅行好きなソフトエンジニアの備忘録

プログラミングや技術関連のメモを始めました

【C#】ToList()の挙動についての勘違い

ToList()が思ってた動作と違ったのでメモしておきます。

↓のようなクラスを作ります。

class MyClass
{
    public MyClass()
    {
        var random = new Random();
        Value = random.Next(100);
    }

    public int Value { get; set; }
}

上記クラスを使って以下のようなコードを書いてしまっていました。 ToList()は新しいリストを作成するので、中身もコピーされると勝手に勘違いしてました。

var myClasses = new List<MyClass>();
for (int i = 0; i < 1000; ++i)
{
    myClasses.Add(new MyClass());
}
// リストからある条件を満たすものを取り出し、コピーしたつもりになっていた
var selectedMyClasses = myClasses.Where(i => i.Value >= 50).ToList();
// 値を書き換えると
selectedMyClasses[0].Value = 10000;
// 元の中身が書き換わってるので、countは1と表示される
int count = myClasses.Count(i => i.Value == 10000);
Console.WriteLine(count);

中身もコピーしたいのであれば、MyClassにコピー用メソッドを加えて

class MyClass : ICloneable
{
    public MyClass()
    {
        var random = new Random();
        Value = random.Next(100);
    }

    public int Value { get; set; }

    public object Clone()
    {
        return MemberwiseClone();
    }
}

↓こんな感じに書くのでしょうか。。。

var myClasses = new List<MyClass>();
for (int i = 0; i < 1000; ++i)
{
    myClasses.Add(new MyClass());
}
var selectedMyClasses = myClasses.Where(i => i.Value >= 50).Select(i => (MyClass)i.Clone()).ToList();
selectedMyClasses[0].Value = 10000;
int count = myClasses.Count(i => i.Value == 10000);
Console.WriteLine(count);

当たり前という突っ込みを受けそうですが、他に同じ質問している人いたので若干ほっとしました。

stackoverflow.com