[C#]データの参照を切りたいとき。

あるデータから一時的なデータを作成したい、とか一時変数にコピーし一時変数だけをいじりたい・・・なんてことを考えたりすることがあります。また、あるデータを引数とする関数を作ったんだけど、その関数内では引数を加工したりするけど、もとのデータ自体には影響したくないぜ!とかあると思う。

ここで問題なのはあるデータというのが何かってこと。値、構造体、クラス・・・。
値渡しや参照渡しっていう言葉を知らなかったり、他の言語の振る舞いになれてしまうと、うっかり変えたくないデータの値が変わってしまうという場合がよくあります。

データクラス

class Person
{
    public string Name{get;set;}
    public string Address{get;set;}
    public string Tel{get;set;}
}

class Persons
{
    public int ManageNumber{get;set;}
    public Person[] List{get;set;}
}

一時的な変数用を用意してからマスターデータをコピーし、一時変数をいじるようにする。

Persons master = GetPersons();

Persons temp = master;

temp.ManageNumber = 4;

上記の方法ではC++では意図した動きになるけど、C#では参照として渡されるだけなので、temp == マスターデータになる。

マスターデータを一時的な引数にして使いたい。

void SetNewData(Persons temp)
{
    tmep.ManageNumber = 4;
}

SetNewData(master);

上記の場合も同じ。C#ではクラス渡しは参照を渡していることと同じなので、マスターデータはそのまま書き換わる。

データのコピーはCloneインタフェースを使用したり、値型で構成された構造体にしたりすることで実現可能だけど、ちょっと面倒くさい。
そこで、少し条件があるけど、マスターデータの値をまるごとコピーする方法を使用する。

どんなオブジェクトでもコピーできる汎用のディープコピー処理
http://d.hatena.ne.jp/tekk/20100131/1264913887

こちらの方のやり方を使用すればデータをまるごとコピーできるので、もとのデータへの参照をぶった切ることができる。
使い方は簡単。object型の拡張メソッドだと次のやり方でOK。

一時変数にコピーする。

Persons master = GetPersons();

Persons temp = (Persons)master.DeepCopy();

temp.ManageNumber = 4;

引数として渡す。


void SetNewData(Persons temp)
{
    tmep.ManageNumber = 4;
}

SetNewData((Persons)master.DeepCopy());

ただし、これには元のデータのクラス宣言に属性を加えないといけない。自分でいじれるクラスでないと使用できないので注意。
Serializable属性を加えたデータクラス

[Serializable()]
class Person
{
    public string Name{get;set;}
    public string Address{get;set;}
    public string Tel{get;set;}
}

[Serializable()]
class Persons
{
    public int ManageNumber{get;set;}
    public Person[] List{get;set;}
}

このデータいじりたくねぇなぁとか、ちょっととっておく、とかいろいろ使い道があるので便利。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


This blog is kept spam free by WP-SpamFree.