C#の値型と参照型の違いを徹底解説!メモリの仕組みとサンプルコードで比較
C#におけるすべての型は、大きく分けて「値型」と「参照型」という2つのカテゴリに分類されます。この2つの違いを正しく理解することは、バグの防止やパフォーマンスの最適化において非常に重要です。本記事では、それぞれの型の特徴、動作の仕組み、そして実際のコード例を使った挙動の違いについて詳しく解説します。
値型とは
値型の変数は、データそのものを直接保持します。各変数が独自のデータコピーを持つため、ある変数の値を変更しても、別の変数やオブジェクトには一切影響しません。
C#における値型には、以下のようなものがあります。
- int、float、double などのすべての数値型
- char 型および bool 型
- struct(構造体)型
- enum(列挙型)
値型は単純に「値そのもの」を格納します。たとえば整数型の場合、変数には数値そのものが入ります。参照型のように「数値へのポインタ(参照)」が格納されるわけではありません。
構造体によるカスタム値型の定義
独自の値型を作成したい場合は、struct を使用します。以下はその例です。
public struct Point
{
public int X;
public int Y;
}
var p1 = new Point();
このとき、Point のインスタンスはメモリ上では次のように表現されます。変数 p1 には X と Y の値がスタック領域に直接格納されているイメージです。

値型の代入動作:値がコピーされる
値型の変数を別の変数に代入すると、代入操作によって値そのものが複製(コピー)されます。
Point p2 = p1;

このように、p1 と p2 はまったく独立した2つのデータを持つことになります。そのため、片方の値を変更しても、もう片方には影響しません。
参照型とは
一方、参照型の変数は、オブジェクトそのものではなくオブジェクトへの参照(アドレス)を格納します。そのため、2つの異なる変数が同じオブジェクトを参照することが可能です。この場合、一方の変数を通じてオブジェクトに行われた変更は、もう一方の変数からも見えることになります。
C#における主な参照型は以下のとおりです。
- String(文字列)
- Class(クラス)
- Array(配列)
- Delegate(デリゲート)
- Interface(インターフェース)
クラスによる参照型の定義
たとえば、参照型であるクラスを作成する場合は以下のように記述します。
public class Point
{
public int X;
public int Y;
}
var p1 = new Point();

参照型の場合、オブジェクトの実体はヒープ領域に配置され、変数にはそのオブジェクトへの参照のみが格納されます。
参照型の代入動作:参照がコピーされる
参照型の変数を別の変数に代入すると、コピーされるのはオブジェクトそのものではなく、参照(アドレス)だけです。
Point p2 = p1;

この結果、p1 と p2 は同じオブジェクトを指すことになります。どちらか一方を経由してプロパティを変更すると、もう一方からもその変更が確認できます。
値型と参照型の挙動を確認するサンプルコード
ここまでの内容を理解するために、値型(struct)と参照型(class)の挙動の違いを1つのプログラムで確認してみましょう。
using System;
class Program
{
static void Main()
{
var p1 = new Point { X = 10 };
Point p2 = p1;
p2.X = 20;
Console.WriteLine("Value Type");
Console.WriteLine(p1.X);
Console.WriteLine(p2.X);
var u1 = new User { Age = 10 };
User u2 = u1;
u2.Age = 20;
Console.WriteLine("Reference Type");
Console.WriteLine(u1.Age);
Console.WriteLine(u2.Age);
}
}
public struct Point
{
public int X;
public int Y;
}
public class User
{
public int Age { get; set; }
}
実行結果
Value Type 10 20 Reference Type 20 20
実行結果の解説
値型(Point 構造体)の場合:p1 を p2 に代入した時点で値がコピーされるため、p2.X を 20 に変更しても p1.X は元のまま 10 です。つまり、両者は完全に独立しています。
参照型(User クラス)の場合:u1 を u2 に代入すると参照が共有されるため、u2.Age を 20 に変更すると u1.Age も 20 になります。両者は同じオブジェクトを指しているからです。
まとめ:値型と参照型の違い一覧
| 項目 | 値型 | 参照型 |
|---|---|---|
| 変数が保持するもの | データそのもの | オブジェクトへの参照 |
| 代入時の動作 | 値がコピーされる | 参照がコピーされる |
| 主な格納場所 | スタック | ヒープ(変数自体はスタック) |
| 代表例 | int、bool、struct、enum | class、string、配列、delegate、interface |
| 他の変数への影響 | なし(独立している) | あり(同一オブジェクトを共有) |
値型と参照型の違いを理解しておくと、「なぜ意図せずデータが書き換わってしまうのか」といったバグの原因特定や、不要なオブジェクト生成を抑えたパフォーマンスチューニングにも役立ちます。用途に応じて struct と class を適切に使い分けましょう。
-
C言語の参照とポインタとは?違いをサンプルコード付きでやさしく解説
はじめに Cプログラミングを学ぶうえで避けて通れないのが「参照」と「ポインタ」の概念です。本記事では、それぞれの特徴・構文・違いを、実際に動くサンプルコードとともにわかりやすく解説します。 参照とは 参照とは、宣言済みの変数につけられた「別名(エイリアス)」のようなものです。主な特徴は次のとおりです。 宣言した変数の別名として振る舞う 値渡し(pass by value)のように扱える null値を持つことができない ※補足:厳密には「参照」はC++の機能であり、純粋なC言語には変数の別名を作る構文は存在しません。C言語で変数を間接的に操作するための仕組みが、後述する「ポインタ」です。
-
具体例でわかる!C言語のvolatile型修飾子とrestrict型修飾子の使い方
型修飾子とは、C言語において既存のデータ型に特別な属性を付与するキーワードのことです。C言語には「const」「volatile」「restrict」の3種類の型修飾子が存在します。本記事では、このうちvolatileとrestrictについて、具体例を交えながらわかりやすく解説します。 volatile型修飾子とは volatile型修飾子は、「その変数が共有されている」ことをコンパイラに伝えるために使用します。つまり、変数をvolatile付きで宣言すると、その変数は他のプログラムやハードウェアなどの外部要因によって参照・変更される可能性があることを意味します。これにより、コンパイラはその