【Unity×C#】「readonly struct」の真の意味とは?ただの書き換え防止じゃない強力な仕組み

Unity

C#で開発していると、「構造体(struct)」という型と、「読み取り専用構造体(readonly struct)」という表記を目にすることがあります。

「読み取り専用ってだけでしょ?」「パフォーマンスが良くなるって本当?」

そんな疑問を持つ方のために、今回はまずstructとは何かから始めて、readonly struct安全性とパフォーマンスの両面でどれだけ重要かを、丁寧に解説していきます。

structの基本

そもそも struct とは?

C#には2つの基本的なデータ型があります。
参照型(class)と値型(struct)です。

class は、実体はメモリの別の場所(ヒープ)に置かれ、変数にはその場所を指し示す参照(ポインタのようなもの)が入ります。

// class(参照型)
public class Person
{
    public string Name;
}
var personA = new Person { Name = "Alice" };
var personB = personA;        // 参照がコピーされる

personB.Name = "Bob";
Console.WriteLine(personA.Name); // → Bob(personBを変えたのにpersonAも変わる)

ここで重要なのは、personB = personA のような代入では、中身そのものはコピーされておらず、参照先の「アドレス(ポインタ)」だけが複製されたという点です。
だからどちらの変数からも同じPersonインスタンスを操作してしまうことになります。

struct は、変数自体が実体そのものを持ちます。他の変数に代入すると、中身が複製されます(=実体のコピー)

// struct(値型)
public struct Point
{
    public int X;
    public int Y;
}
var pointA = new Point { X = 1, Y = 2 };
var pointB = pointA;          // 実体がコピーされる

pointB.X = 100;
Console.WriteLine(pointA.X);  // → 1(pointAとpointBは別物)

Point のような構造体(値型)は、代入のたびに中身が完全にコピーされる(別物が複製される)ため、後から一方を変更してももう一方には影響がありません。

🧱 structは「軽くて独立した値」を表すのに適している

C#では、短命で軽量なデータ(たとえば座標、色、サイズなど)を表現したいときに struct を使います。
ただし、値がコピーされる(=複製される)性質を持つため、うっかり書き換えをすると「えっ、変わってない?」というトラブルに繋がることもあります。

そこで登場するのが、readonly struct です。

readonly structとは?

readonly struct は、その構造体が絶対に書き換わらないことをC#コンパイラに保証させるための宣言です。

たとえばこんなコード。

public readonly struct Position
{
    public int X { get; }
    public int Y { get; }

    public Position(int x, int y)
    {
        X = x;
        Y = y;
    }
}

このように readonly をつけると、

  • フィールドやプロパティがすべて読み取り専用でなければならない
  • 外部からの書き換えも、内部からの書き換えも不可能になる

つまり「イミュータブル(不変)な値オブジェクト」として設計できるわけです。

⚠️ readonly structの値を変えようとすると?

以下のように、読み取り専用のフィールドを変更しようとするとエラーになります。

var p = new Position(1, 2);
p.X = 10;  // コンパイルエラー

これは readonly によって「この構造体は絶対に変更してはならない」と明示されているためです。

一度生成したら中身を変えない。
これが readonly struct の基本思想です。

パフォーマンスにも効果あり!

readonly struct は単なる「書き換え禁止マーク」ではありません。
C#のコンパイラやJIT(実行時コンパイラ)に「これは安全だからコピーを減らしていいよ」と伝える働きもあります。

通常の struct はメソッド内でフィールドにアクセスしたりプロパティを使うだけで、勝手にコピー(複製)が発生してしまうことがあります。
これは、構造体がメモリの別の場所にあるかもしれないとき、安全のためにコピーしてから使う設計になっているためです。

しかし readonly struct なら「どうせ絶対に中身は変わらない」と確定しているので、不要なコピー処理が最適化によって省かれる可能性が高まります。
つまり、速くて軽いコードが書けるようになるというわけです。

書き換えられるstructは避けるべき?

これはC#界隈では「ほぼYES」だそうです。

public struct Counter
{
    public int Count;

    public void Increment()
    {
        Count++;
    }
}

このような「書き換える構造体」は、たとえば List<Counter> などに入れて操作すると、コピーに対して操作してしまい、リスト中のデータが変わっていないということが簡単に起きます。この使い方は完全に禁忌です。

C#において、構造体は「読み取り専用」である前提の設計が基本。
「値を変えたいならclassにすべき」とよく言われるのはこのためです。


まとめ:readonly structは明確な意図とメリットを持った設計

  • readonly struct は「変更禁止」+「パフォーマンス改善」のダブル効果を持つ
  • 構造体は値型。代入や引数渡しで中身がコピー(複製)されるため、意図せぬ変更が発生しやすい
  • readonly にすることで、不変性が保証され、安全性も速度もアップ
  • 「変更が必要」なら、それは class を使うべき設計のサイン

特にUnityなどのゲーム開発では、パフォーマンスや明快なデータ構造が求められる場面が多いため、
「迷ったらreadonly struct」→「変更したいならclass」という指針は非常に有効です。

Unity/C# をもっと体系的に学ぶには?
【現役メンターに質問しながら短期集中】
👉️ Unityコースで学んでみる

タイトルとURLをコピーしました