プロパティの値を変更したけど変わらない・・・
職場においてC#を利用して自社サービスを実装しているのですが、IEnumerable
ではまったことをちょっとまとめておきたいと思います。
下記は起こった事象を簡単にしたものとなります。下記の例は、IEnumerable
に入ったユーザ情報の名前が大文字になることを期待したものとなります。
// このようなクラスを読み込んでいます//class User {// public string Name { get; set; }//}IEnumerable<User>users=new[]{"kato","saito","kondo"}.Select(n=>{returnnewUser{Name=n};});foreach(Useruserinusers){// 大文字に変換したはずなのに・・・user.Name=user.Name.ToUpper();}foreach(Useruserinusers){Console.WriteLine(user.Name);}
出力結果
kato
saito
kondo
なぜか最初の値のままでした・・・
そうなんです。参照が違っておりました。Enumerable.Repeat
とかEnumerable.Select
とかが遅延評価のIEnumerable
を返すので、foreach
やToList
で評価された際に初期化されてしまいます。
修正パターン1
IEnumerable<User>users=new[]{"kato","saito","kondo"}.Select(n=>{returnnewUser{Name=n};}).ToList();foreach(Useruserinusers){// 大文字に変換user.Name=user.Name.ToUpper();}foreach(Useruserinusers){Console.WriteLine(user.Name);}
ToList()することで再度評価されても同じ参照が返るので無事、大文字にできました。
KATO
SAITO
KONDO
修正パターン2
修正パターン1だと、2ループしてしまうのは性能上問題があると思いますので、下記の方法を考えました。
IEnumerable<User>users=new[]{"kato","saito","kondo"}.Select(n=>{returnnewUser{Name=n};});users=users.Select(u=>{u.Name=u.Name.ToUpper();returnu;});foreach(Useruserinusers){Console.WriteLine(user.Name);}
初期化の後にSelect()に修正して、無事、
KATO
SAITO
KONDO
大文字に置換することができました!
実行環境
- C# 7.3
- Windows 10