概要

型には値型と参照型の2種類があります。

値型

データの値そのものを保持する型を値型といいます。
構造体・列挙型が該当します。

構造体(struct)

structキーワードを付与して定義されたものは構造体となり、値型として扱われます。

public struct Hoge
{
     public int Value;
}

列挙型(enum)

enumキーワード付与して定義されたものは列挙型となり、値型として扱われます。

public enum Hoge
{
     Value,
}

値型の動作

値型は値そのものなので、nullになりません。
変数などで宣言した時点で初期値を持ちます。
内包する要素も各々の型のデフォルト値で初期化されます。
以下コードでは「0」が出力されます。

Hoge hoge;
Console.WriteLine(hoge.Value);

また、他の変数・プロパティなどに代入した時点で、それぞれ別物として扱われます。
以下のコードでは各変数のValueはそれぞれ異なる値になります。

Hoge hoge1 = new Hoge();
Hoge hoge2 = hoge1;
Hoge hoge3 = hoge2;
hoge1.Value = 1;
hoge2.Value = 2;
hoge3.Value = 3;

値型はスタックメモリ上で管理されます。
ただし、値のスコープがメソッド内など明確に限定されるケースのみで、
クラスメンバ・クロージャなどの場合はヒープメモリ上で管理されます。

参照型

データへの参照を保持する型を参照型といいます。
クラスなどが該当します。

クラス(class)

classキーワードを付与して定義されたものはクラスとなり、参照型として扱われます。

public class Hoge
{
    public int Value;
}

参照型の動作

参照型は参照を保持するため、宣言しただけでは何の参照も保持しておらず、nullになります。

Hoge hoge;
// 未初期化変数へのアクセスでコンパイルエラーになる
Console.WriteLine(hoge.Value);

また、他の変数・プロパティに代入しても全て同じインスタンスを参照します。
以下のコードでは各変数のValueは全て3になります。

Hoge hoge1 = new Hoge();
Hoge hoge2 = hoge1;
Hoge hoge3 = hoge2;
hoge1.Value = 1;
hoge2.Value = 2;
hoge3.Value = 3;

参照型はヒープメモリ上で管理されます。

スタック・ヒープ

かなりざっくりした解釈ですが、まとめておきます。

スタック
  • 先入れ後出しで情報を管理するメモリ領域
  • 高速だが、領域サイズに制限があるため、大きいデータを扱うには不向き
  • 先入れ後出しのため、メモリ開放順序がランダムになるようケースでは使えない
    →クラスメンバ・クロージャが扱えないのはこのため
ヒープ
  • 任意の順序で情報を管理するメモリ領域
  • 低速だが、領域サイズを大きく取れるため、大きいデータを扱える
  • 先入れ先出しのような制約がないため、メモリ開放順序がランダムになるケースで使える