- ベストアンサー
C#でのオブジェクトのコピーについて
- C#でのオブジェクトのコピー方法を調査しています。参照渡しではなく値渡しでオブジェクトをコピーしたいと思っています。コピーする際にリストを使用する場合にはどのように記述すれば良いのか教えてください。
- C#でオブジェクトのコピーについて質問です。リストを使用しない場合は、深いコピーを行うことができましたが、リストを使用する場合には一部のプロパティの値まで変更されてしまいます。リストを使用する際にも正しくオブジェクトをコピーする方法を教えてください。
- C#でオブジェクトのコピーを行う際、参照渡しではなく値渡しにしたいと考えています。リストを使用する場合に値までコピーする方法がわかりません。リストを使用する場合にも正しくオブジェクトをコピーする方法を教えていただきたいです。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
> tc.cc1 = cc1; > tc.cc2 = cc2; これでは浅いコピーになってしまいます。 とりあえず,私だったらこうする程度の物を。 # U+0009/U+0020が無視されるので,U+3000に置き換えています。 public class TestClass { public int n; public ChildClass1 cc1; public List<ChildClass2> cc2; public TestClass () { n = 0; cc1 = new ChidlClass1(); cc2 = new List<ChildClass2>(); } protected TestClass (TestClass other) { n = other.n; cc1 = other.cc1.Clone(); // cc1の深いコピー cc2 = new List<ChildClass2>(other.cc2.ConvertAll(item => item.Clone())); // cc2の深いコピー : List<T>の要素単位でCloneする } public TestClass DeepCopy () { return TestClass(this); tc.cc1 = (ChildClass1)cc1.Clone(); for (int i = 0; i < cc2.Count; i++) { tc.cc2[i] = (ChildClass2)cc2[i].Clone(); } return tc; } } public class ChildClass1 : ICloneable { public int i; public ChildClass1 () : this(0) { } public ChildClass1 (int value) { i = value; } protected ChildClass1 (ChildClass1 other) { i = other.i; } public ChildClass1 Clone () { return new ChildClass1(this); } object ICloneable.Clone () { return Clone(); } } public class ChildClass2 : ICloneable { public int i; public ChildClass2 () : this(0) { } public ChildClass2 (int value) { i = value; } protected ChildClass2 (ChildClass1 other) { i = other.i; } public ChildClass2 Clone () { return new ChildClass1(this); } object ICloneable.Clone () { return Clone(); } }
その他の回答 (2)
- Yune-Kichi
- ベストアンサー率74% (465/626)
item => item.Clone() としないと,Listが同一のChildClass2への参照を保持したままになります。 四角と矢印を使って,現在どの変数がどのオブジェクトを参照しているかを図示しながら追ってみるとよいと思います。 お試し) using System; using System.Collections.Generic; class Program { static void Main (string[] args) { TestClass tc1 = new TestClass(); tc1.cc2.Add(new ChildClass2(10)); Console.WriteLine(tc1.cc2[0].i); TestClass tc2 = tc1.DeepCopy(); tc2.cc2[0].i = 15; Console.WriteLine(tc1.cc2[0].i); } } public class TestClass { public int n; public ChildClass1 cc1; public List<ChildClass2> cc2; public TestClass () { n = 0; cc1 = new ChildClass1(); cc2 = new List<ChildClass2>(); } protected TestClass (TestClass other) { n = other.n; cc1 = other.cc1.Clone(); // cc1の深いコピー cc2 = new List<ChildClass2>(other.cc2.ConvertAll(item => item)); // cc2の浅いコピー : List<T>の要素をそのまま代入 } public TestClass DeepCopy () { return new TestClass(this); } } public class ChildClass1 : ICloneable { public int i; public ChildClass1 () : this(0) { } public ChildClass1 (int value) { i = value; } protected ChildClass1 (ChildClass1 other) { i = other.i; } public ChildClass1 Clone () { return new ChildClass1(this); } object ICloneable.Clone () { return Clone(); } } public class ChildClass2 : ICloneable { public int i; public ChildClass2 () : this(0) { } public ChildClass2 (int value) { i = value; } protected ChildClass2 (ChildClass2 other) { i = other.i; } public ChildClass2 Clone () { return new ChildClass2(this); } object ICloneable.Clone () { return Clone(); } } 出力) 10 15 ちなみに,Cloneすると 10 10 が正しく得られます。
お礼
ご返答ありがとうございます。 なるほど、たしかにこれだと変化しますね。 確認してみたのですが、自分はこちらを使って試していました・・・ public TestClass DeepCopy() { TestClass tc = new TestClass(this); tc.cc1 = (ChildClass1)cc1.Clone(); for (int i = 0; i < cc2.Count; i++) { tc.cc2[i] = (ChildClass2)cc2[i].Clone(); } return tc; } だからここでクローン作成していたから変化しなかったんだと思います。 参考になりました。
- Yune-Kichi
- ベストアンサー率74% (465/626)
DeepCopyといいつつ,cc2がMemberwiseCloneでしかコピーされていません。 この結果,cc2がtc1とtc2で共有されてしまい,tc1.cc2[0].iとtc2.cc[0].iが同じ値になっています。 MemberwiseCloneを使わずに実装することをお勧めします。
お礼
ご返答ありがとうございます。 >MemberwiseCloneを使わずに実装することをお勧めします。 一応、次のようなメンバを一つ一つコピーするやり方でやってみたのですが、やっぱり同じ結果でした・・・ 自分の理解ミスだと思いますが、こういうやり方ではないのでしょうか? public class TestClass { public int n; public ChildClass1 cc1 = new ChildClass1(); public List<ChildClass2> cc2 = new List<ChildClass2>(); public object DeepCopy() { TestClass tc = (TestClass)Clone(); tc.cc1 = (ChildClass1)cc1.Clone(); for (int i = 0; i < cc2.Count; i++) { tc.cc2[i] = (ChildClass2)cc2[i].Clone(); } return tc; } private object Clone() { TestClass tc = new TestClass(); tc.cc1 = cc1; tc.cc2 = cc2; return tc; //return MemberwiseClone(); } } public class ChildClass1 : ICloneable { public int i; public object Clone() { ChildClass1 cc1 = new ChildClass1(); cc1.i = i; return cc1; //return MemberwiseClone(); } } public class ChildClass2 : ICloneable { public int i; public object Clone() { ChildClass2 cc2 = new ChildClass2(); cc2.i = i; return cc2; //return MemberwiseClone(); } }
お礼
ご返答ありがとうございます。 試してみましたができました。ありがとうございます。 ところで、まだあまり理解しきれてない中、いろいろ試してみたのですが other.cc2.ConvertAll(item => item.Clone()) を other.cc2.ConvertAll(item => item) で実行してもできた(変更されない)のですが、これはなぜなのでしょうか? できたとしてもこのような記述は良くないのでしょうか?