ごまなつ Blog

楽しく働ける世界を目指して

【C#】クラスの配列要素の代入は、シャローコピーになる

C#で、xmlファイルをシリアライズ・デシリアライズするためのクラスを宣言して、その内容を変更していました。そこで、配列要素の代入なのにシャローコピーに苦しめられたのでメモです。

public class exampleclass
    {
        [System.Xml.Serialization.XmlElement("version")]
        public string version { get; set; }
        [System.Xml.Serialization.XmlElement("id")]
        public string mapid { get; set; }
        [System.Xml.Serialization.XmlElement("name")  
        public string mapname { get; set; }
        [System.Xml.Serialization.XmlElement("element")]
        public List<band> element { get; set; }
    }

public exampleclass[] Array1 = new Chmap[1000

要素名は適当ですが、このようなクラスがあり、そのクラスの2つの配列を宣言します。この後、

Array1[4] = Array1[0]
Array1[4].version = "1.99"

のように要素を別のインデックスにコピーした後、その要素を変更します。すると、Array1[0].versionも"1.99"に変更されてしまいます。

ディープコピーとシャローコピー

ディープコピー(深いコピー)とシャローコピー(浅いコピー)の違いは、簡単に言うとコピー先の変更がコピー元にも反映されるのがシャローコピー、そうでないのがディープコピーです。シャローコピーは参照をコピーしているだけなので、同じものを参照しているのでどちらも変更された後の配列を参照していることになります。

C#では、配列やリストを=で代入すると、シャローコピーになります。配列やリストは参照型です。int,doubleといった値は値型なのでディープコピーになります。

では配列やリストをどうやってディープコピーするのかですが、配列はArray.Copy,リストはコンストラクタで宣言します。

int[] a = new int[5]
int[] b = new int[5]
Array.Copy(a, b, a.Length)

var list  = new List<int>{1,2}
var list2 = new List<int>(list)

これで良いかと思われたのですが、今回のクラスの場合のような多重構造になると、直下はディープコピーになりますが、それ以降の階層ではシャローコピーになります。

参考にしたページ qiita.com

自分が採用した方法

こちらのページのメソッドを使用しました。

l-s-d.sakura.ne.jp

多重構造でもディープコピーしたい場合は自力で実装するしかないようです。MemoryStreamを用いてシリアライズ・デシリアライズしているようです。