この章のテーマ §
値型と参照型という言葉はソースコード上に出てきませんが、APIの説明などには頻出します。
知っておくとそれだけでトラブルを未然に防止できるキーワードです。
前提知識 §
Console.Writeメソッド, データ型の基礎, 変数の基礎, int型,代入文, new 演算子
解説 §
C#の全てのデータ型は2つに分類できます。値型と参照型です。
値型と参照型はデータの格納方法の違いを示します。
値型は、その値そのものを扱います。ですから、変数をクリアすると値そのものが消えます。
参照型は、その値が入っている住所を扱います。ですから、変数をクリアすると消えるのは住所の情報だけで値そのものは消えません。他の誰かが使っている限り、値は残り続けます。
なぜ2つの方法があるのかと言えば、値型の方が効率が良い場合と、参照型の方が効率のよい場合があるからです。
値型は代入が発生すると常にデータ全体の複製を作ります。データのサイズが大きいと非常に大きな時間が掛かります。参照型だと住所情報だけ複製を作るので迅速です。
一方で、参照型は常にデータ本体の他に住所情報を扱うため、管理が複雑になり、メモリも余計に必要とされます。小さなデータを大量の扱う場合は、メモリを消費しない値型の方が効率良く扱える場合があります。
値型の代表例は数値です。
参照型の代表例は、文字列などです。
一般的にclassキーワードで宣言されたものは参照型、structキーワードで宣言されたものは値型です。
サンプルソースは、【参照型=住所の複製】と【値型=住居の複製】の違いを示しています。
参照型の場合、複製されたのは住所ですから、住居に入っている人が123さんから456さんに変われば誰が問い合わせても住人は456さんです。
しかし、値型は住居を複製するので、123さんが住んでいる住居と、456さんが住んでいる住居の2つが発生します。
参照型と値型でほぼ同じプログラムが書いてありますが、結果が異なることに注意して下さい。ここを間違うとプログラムが思い通りに動きません。
罠の数々 §
値型を参照型であるかのように扱うようにできる【ボックス化】という機能があることに注意しましょう。【ボックス化】は値型をobject型の変数などに格納すると発生します。キャストなどで元の型に戻すと【ボックス化解除】が行われて値型に戻ります。
参考リンク §
参照型 (C# リファレンス)
値型 (C# リファレンス)
サンプルソース: valref §
// 参照型の場合
Console.WriteLine("参照型の場合");
T1 t1 = new T1();
t1.A = 123;
T1 copy1 = t1;
t1.A = 456;
Console.WriteLine($"t1.A={t1.A} copy1.A={copy1.A}");
// 値型の場合
Console.WriteLine("値型の場合");
T2 t2 = new T2();
t2.A = 123;
T2 copy2 = t2;
t2.A = 456;
Console.WriteLine($"t2.A={t2.A} copy2.A={copy2.A}");
// 参照型の型の宣言
class T1
{
internal int A { get; set; }
}
// 値型の型の宣言
struct T2
{
internal int A { get; set; }
}
実行結果 §
参照型の場合
t1.A=456 copy1.A=456
値型の場合
t2.A=456 copy2.A=123
リポジトリ §
https://github.com/autumn009/CSharpPrimer2
練習問題 §
天才くんが凄いアイデアを思い付いた。
「参照型は常に住所だけ記録するので少ないメモリで大サイズの値を示すことができる。それなら、住所だけファイルに保存しておけばファイルが小さくて済むぞ」
この天才くんのアイデアは正しいだろうか?
間違っているだろうか?
間違っているとしたら理由は何だろうか?
[[解答]]