C#の変数型には値型と参照型の2種類があることはみなさんご存知だと思います。
その2つの扱いについて少しまとめてみました。
おさらい
値型
値型は数値型や構造体(struct)によくあるもので、引数の指定とかするとデータが毎回コピーされます。
そのため、引数の指定にでかい構造体を指定するようにすると、ものすごいコストがかかるようになります。
参照型
参照型はいわゆるポインター。引数の指定とかではメモリのアドレスが渡されるだけでデータはメモリ上のどこかに存在します。
なので極端な話、1MBとかのデータを引数で渡すときも参照としてわたしてあげると、実際に渡されるデータは1,2バイトです。
文字列型について
文字列型は、一応参照型なのですが結構特殊な存在で、文字列を操作するときに毎回コピーされてから処理されます。
つまりは参照型・値型の両方を持ち合わせた存在だと言えます。
逆にstring型ではなくStringBuilder型を使うことで完全な参照型にしてあげることもできます。
ボクシング(Boxing)
もともと値型であるデータを、一応程度の参照型にしてあげることもできます。
やり方は単純で、データをobjectに変換してあげるだけ。
// なんかの構造体 StructData data = new StructData(); // ボクシング object obj = (object)data;
ただ、これにも問題があり、巨大な構造体をボクシングするのはいいのですが、データを取り出すたびに毎回、元の型に変換して上げる必要があるため、かなりコストの高い処理といえます。
ちなみに引数で値型を参照渡しする場合はrefをつけてあげるだけです。
比較について
比較は引数に渡される時と同じ状態で比較されます。つまり、値型はデータを比較、参照型はアドレス同士で比較するわけです。
値型の場合
int val1 = 100, val2 = 200; if (val1 == val2) // trueになる Console.WriteLine("true"); else Console.WriteLine("false");
普通の数値型で考えると簡単ですね。100と200で比較すれば当然falseになります。
この、データをそのまま比較するということでポイントで、構造体でも同じように、中身の値が同じなら別のインスタンスでもtrueになります。
参照型の場合
さて、問題の参照型。問題というほどでもないですが…初心者が陥りやすい
こちらの場合は、別のインスタンスなら内容が同じいでもfalseになります。なぜならアドレスを比較しているから。
例えば、これは別インスタンスのためfalseになります。
static void Main(string[] args) { ClassData data1 = new ClassData() { Val = 100 }; ClassData data2 = new ClassData() { Val = 100 }; if (data1 == data2) Console.WriteLine("true"); else Console.WriteLine("false"); } internal class ClassData { internal int Val = 100; }
あと、これはボクシングした値型にも同じように言えます。
if ((object)100 == (object)100) Console.WriteLine("true"); else Console.WriteLine("false");
こちらもfalseとなります。なぜ?それはそれぞれの100を各自でボクシングしたからアドレスが違うのです。