【C#入門】値型と参照型は「コピーを渡すか?住所を渡すか?」で完全に理解する
C#を学び始めると、値型(Value Type)と参照型(Reference Type)の違いで迷うことがあります。
まず覚えてほしいポイントは、次の2つです。
- 値型の変数を代入すると、値そのものがコピーされる
- 参照型の変数を代入すると、同じ実体を見るための参照がコピーされる
この記事では、参照を分かりやすくするために「住所(リンク)」と表現します。ただし、これは生のメモリアドレスそのものではなく、オブジェクトを参照するための情報を表す比喩です。
1. 値型と参照型の違いは「何がコピーされるか」
どちらの場合も代入ではコピーが行われます。違うのは、コピーされるものです。
| 種類 | 代入でコピーされるもの | コピー後の関係 |
|---|---|---|
| 値型 | 値そのもの | それぞれが独立した値を持つ |
| 参照型 | オブジェクトへの参照 | 複数の変数が同じ実体を参照できる |
「値型か参照型か」は、必ずスタックかヒープかで分類するものではありません。本質は、変数が値そのものを保持するか、オブジェクトへの参照を保持するかです。
配置場所まで詳しく学びたい場合は、C#のメモリ管理入門|スタック・ヒープ・値型・参照型を初心者向けに解説を参照してください。
2. 値型:値そのものをコピーする
代表的な値型には、int、float、double、bool、char、enum、structなどがあります。
地図をコピーして渡すイメージ
あなたが持っている地図をコピーして、友人に渡したとします。友人が自分の地図に書き込んでも、あなたの地図は変わりません。2枚は同じ内容から始まりますが、コピー後は別々のものです。
int a = 5;
int b = a; // aの値「5」をコピー
b = 10;
Console.WriteLine(a); // 5
Console.WriteLine(b); // 10
bを変更してもaが変わらないのは、2つの変数がそれぞれ独立した値を持っているからです。
3. 参照型:同じ実体への参照をコピーする
代表的な参照型には、class、配列、List、string、delegateなどがあります。
家の住所を渡すイメージ
家は1軒だけあり、あなたと友人が同じ家の住所を知っているとします。友人がその家の家具を動かせば、あなたが家を見たときにも家具は移動しています。
参照型でも「コピーされない」わけではありません。オブジェクトそのものではなく、同じオブジェクトを見るための参照がコピーされます。
class Data
{
public int Value;
}
Data a = new Data();
a.Value = 5;
Data b = a; // aが持つ参照をコピー
b.Value = 10;
Console.WriteLine(a.Value); // 10
Console.WriteLine(b.Value); // 10
aとbは別々の変数ですが、同じDataオブジェクトを参照しています。そのため、b経由の変更をaからも確認できます。
stringは参照型だが、値型のように見える
stringは参照型ですが、作成後の文字列の内容を変更できない不変(immutable)な型です。文字列を変更する操作では新しい文字列が作られるため、値型のように独立して見えることがあります。
詳しくは、stringは参照型なのに、なぜコピーしても影響しないの?で確認できます。
4. 図で確認:値のコピーと参照のコピー

図を使ってさらに確認したい場合は、【図で理解】値型と参照型のメモリ構造もおすすめです。
5. Unityで起きやすい混乱
5-1. transform.position.xを直接変更できない理由
transform.position.x = 5; // コンパイルエラー
Vector3は構造体、つまり値型です。さらにTransform.positionはプロパティであり、取得するとVector3の値が返されます。返された一時的な値のxだけを書き換えても、変更先へ戻せないためエラーになります。
いったん変数へ取り出し、変更後の値をプロパティへ戻します。
Vector3 position = transform.position;
position.x = 5;
transform.position = position;
5-2. ScriptableObjectは参照型
ScriptableObjectは参照型なので、複数の場所が同じインスタンスを参照していると、一方から行った変更をほかの場所からも確認できます。
ただし、「参照型だから変更が必ずアセットへ永続保存される」という意味ではありません。Editor上のアセット、再生中に生成したインスタンス、ビルドしたアプリでは扱いが異なります。保存されるかどうかは、どのインスタンスを変更したか、Editorのシリアライズ対象か、明示的な保存処理を行ったかによって決まります。
6. 確認問題
int b = a;の後でbを変更しました。aも変わりますか?Player b = a;の後でb.Hpを変更しました。a.Hpからも変更を確認できるのはなぜですか?
答えを確認する
1. 変わりません。値そのものがコピーされ、別々の値になるからです。
2. aとbが、同じPlayerオブジェクトへの参照を持っているからです。
7. まとめ
- 値型:値そのものがコピーされ、コピー後は独立する
- 参照型:参照がコピーされ、複数の変数が同じ実体を参照できる
- 「住所」は理解のための比喩であり、生のメモリアドレスそのものではない
- 値型/参照型の違いと、スタック/ヒープの配置は分けて考える
newとの関係まで学びたくなったら、C#のnewを理解する――値型・参照型・スタック・ヒープの関係へ進んでください。










ディスカッション
コメント一覧
まだ、コメントがありません