C#の構造体(Struct)って実際なに?

C# の struct は、値型として扱われる軽量なデータ構造です。
クラス(class)と似ていますが、メモリ管理や用途に明確な違いがあります。

struct の基本

struct値型(Value Type) であり、変数に代入したりメソッドに渡したりすると コピーが作られます

宣言例

csharp
public struct PlayerStatus
{
    public int hp;
    public int mp;

    public PlayerStatus(int hp, int mp)
    {
        this.hp = hp;
        this.mp = mp;
    }
}

特徴まとめ

  • 値型(スタックに配置されやすい)
  • 継承不可(インターフェースの実装は可能)
  • デフォルトコンストラクタを定義できない
  • 小さくて不変なデータに向く

struct と class の違い

メモリ管理の違い

  • struct:値型 → コピーされる
  • class:参照型 → 参照が渡される
csharp
struct A { public int x; }
class B { public int x; }

A a1 = new A { x = 10 };
A a2 = a1;   // 値がコピーされる
a2.x = 20;   // a1.x は 10 のまま

B b1 = new B { x = 10 };
B b2 = b1;   // 参照がコピーされる
b2.x = 20;   // b1.x も 20 に変わる
⚡ IMPORTANT
struct はコピーされるため、意図せず値が変わらないことがある。
class と同じ感覚で扱うとバグの原因になる。

struct を使うべきケース

struct が向いている場面

  • 小さくて不変なデータ
    例:座標、色、短いステータス情報

  • 頻繁に生成される軽量データ
    → GC 負荷を減らせる

  • Unity での軽量データ構造
    Vector3Quaternion なども struct

💡 TIP
struct は 16 バイト以下が推奨とされることが多い。
大きすぎる struct はコピーコストが高くなる。

struct を避けるべき場面

  • 大きなデータを持つ
  • ミュータブル(可変)なデータ
  • 継承を使いたい
  • 参照共有したい

readonly struct / ref struct

readonly struct

不変データを表すための構造体。

csharp
public readonly struct Damage
{
    public int Value { get; }
    public Damage(int value) => Value = value;
}
ℹ️ NOTE
フィールドも自動的に readonly として扱われるため、安全性が高い。

ref struct

スタック上にしか置けない特殊な struct。
Span<T> などが代表例。

⚠️ WARNING
ref struct はクラスのフィールドにできないなど制約が多い。

実用例(ゲーム・業務アプリ・Unity)

1) ゲーム開発:座標やステータスの軽量管理

csharp
public struct Position
{
    public float x;
    public float y;

    public Position(float x, float y)
    {
        this.x = x;
        this.y = y;
    }
}

public class Enemy
{
    public Position pos;
    public int hp;

    public void Move(float dx, float dy)
    {
        pos.x += dx;
        pos.y += dy;
    }
}
💡 TIP
座標のような「小さくて頻繁に使うデータ」は struct が最適。

2) 業務アプリ:不変データの表現(readonly struct)

csharp
public readonly struct Money
{
    public decimal Amount { get; }
    public string Currency { get; }

    public Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }
}

Money price = new Money(1200m, "JPY");
⚡ IMPORTANT
金額や日付など「不変であるべきデータ」は readonly struct が安全。

3) Unity:物理計算や軽量データの受け渡し

csharp
public struct HitInfo
{
    public Vector3 point;
    public float damage;

    public HitInfo(Vector3 point, float damage)
    {
        this.point = point;
        this.damage = damage;
    }
}

void OnHit(HitInfo hit)
{
    Debug.Log($"Hit at {hit.point}, damage={hit.damage}");
}
🔴 CAUTION
struct を引数で渡すとコピーされるため、巨大な struct は避ける。

まとめ

  • struct は 軽量な値型データ を表すのに最適
  • コピーされる性質を理解して使うことが重要
  • 不変データ・小さなデータに向く
  • Unity でも頻繁に利用される
  • 実用例として「座標」「金額」「ヒット情報」などが典型