
visual studio 2008 express edition
C#3.5
を使用しています。
参照渡しではなく値渡し(コピー元が影響されない)でオブジェクトをコピーしたいと思い、
次のようなかんじで深いコピーを行ったのですが、
tc1.cc1.i(リストを使用しない方)変更されなかったのですが
tc1.cc2[0].i(リストを使用した方)は変更されてしまいます・・・
どこが原因で、リストを使用する場合はどのように記述すれば良いのでしょうか?
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()
{
return MemberwiseClone();
}
}
public class ChildClass1 : ICloneable
{
public int i;
public object Clone()
{
return MemberwiseClone();
}
}
public class ChildClass2 : ICloneable
{
public int i;
public object Clone()
{
return MemberwiseClone();
}
}
TestClass tc1 = new TestClass();
tc1.cc1.i = 1;
ChildClass2 cc2 = new ChildClass2();
cc2.i = 1;
tc1.cc2.Add(cc2);
TestClass tc2 = (TestClass)tc1.DeepCopy();
tc2.cc1.i = 2;
tc2.cc2[0].i = 2;
System.Windows.Forms.MessageBox.Show("cc1.i = " + tc1.cc1.i + " cc2[0].i = " + tc1.cc2[0].i);// cc1.i = 1 cc2[0].i = 2←変更されてしまう
No.2ベストアンサー
- 回答日時:
> 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();
}
}
ご返答ありがとうございます。
試してみましたができました。ありがとうございます。
ところで、まだあまり理解しきれてない中、いろいろ試してみたのですが
other.cc2.ConvertAll(item => item.Clone())
を
other.cc2.ConvertAll(item => item)
で実行してもできた(変更されない)のですが、これはなぜなのでしょうか?
できたとしてもこのような記述は良くないのでしょうか?
No.3
- 回答日時:
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;
}
だからここでクローン作成していたから変化しなかったんだと思います。
参考になりました。
No.1
- 回答日時:
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();
}
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- C言語・C++・C# 大量のデータを読み込んで表示する速度を改善したい 8 2023/05/07 13:29
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- C言語・C++・C# Windows Formアプリからコンソールを呼び出して文字を出力させたい 8 2023/05/09 10:53
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# クラスのメンバ変数を基準に並べ替えをしたい 5 2022/12/25 17:40
- Java java final 1 2022/06/10 22:49
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- C言語・C++・C# C# DatagridviewにExcelシートを反映するとエラーが出る 2 2023/05/06 17:12
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
透過色について
-
c# スレッド間でのデータの共有
-
C#で、あるクラスのメンバーす...
-
フレームを表示できないのです...
-
JAVAアプレットのサウンド機能...
-
Javaのマウスイベントについて
-
Javaのアプレットについて
-
C# 親フォームで指定した値を...
-
JTable で複数行の編集
-
正規表現
-
★滑らかな画像切り替え★
-
大量のデータを読み込んで表示...
-
javaで時刻の判定
-
JAVAの問題
-
DocumentListenerについて
-
長方形をドラッグするJavaアッ...
-
BufferedImageへの変換エラーです
-
【C#】ソースコードをファイル...
-
public でないObjectはXMLEncod...
-
C# visibleプロパティをfalseに...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
大量のデータを読み込んで表示...
-
ボタンの複数割り当てについて
-
C#で、あるクラスのメンバーす...
-
C#で別のFormへ複数の値を返そ...
-
C# WinForm のDataGridView Cel...
-
C# visibleプロパティをfalseに...
-
C# 矢印キーの取得
-
C# MouseHoverを何度も呼ぶには
-
Junitテストでvoid戻り値メッソ...
-
C#でのWNetAddConnection3の使...
-
C#でキーイベントが発生しない...
-
C# DataGridView列カスタマイズ
-
C#から、C++で作成したdll内の...
-
画像ファイル操作方法
-
エンターキーを押すとOKボタン...
-
スレッド動かず
-
Java コレクション・ジェネリク...
-
なぜエラーになるのかがわかり...
-
マウスクリックで別のスレッド...
-
参照されない
おすすめ情報