C#構造体とクラスの違いと使い分け

初心者が知っておくべき基本と選び方の指針


はじめに

C#では、構造体(struct)とクラス(class)の両方を使って独自の型を定義できます。見た目は非常に似ていますが、挙動や使いどころが大きく異なるため、正しい理解が必要です。

本記事では、それぞれの特徴・違い・選び方の目安を、初心者にもわかりやすく解説します。


1. 構造体とクラスの定義

クラス(class)の例

class Player
{
    public string Name;
    public int HP;
}

構造体(struct)の例

struct Position
{
    public float X;
    public float Y;
}

見た目は似ていますが、使われ方やメモリの扱いが違います。


2. 大きな違い:値型と参照型

特徴構造体(struct)クラス(class)
メモリ分類値型参照型
保管場所スタックヒープ
コピー値のコピー参照のコピー
初期化newは省略可new必須
継承できない可能

値型とは?

値型は中身がコピーされるタイプ。int, float, boolなどと同じ。

Position a = new Position { X = 5, Y = 10 };
Position b = a;  // 値をコピー
b.X = 20;

Console.WriteLine(a.X);  // → 5(元は変わらない)

参照型とは?

参照型はアドレス(参照)をコピーするタイプ。

Player a = new Player { Name = "勇者", HP = 100 };
Player b = a;  // 同じオブジェクトを参照
b.HP = 0;

Console.WriteLine(a.HP);  // → 0(aも影響を受ける)

3. 構造体が向いているケース

  • 小さくて軽いデータ(例:座標、色、サイズなど)
  • 不変の値(immutable)に近い用途
  • 頻繁なインスタンス生成・破棄が必要なケース

UnityのVector2, Color, Rectも構造体です。


4. クラスが向いているケース

  • 状態の変化を持つオブジェクト
  • 継承・ポリモーフィズムが必要な設計
  • 多くのプロパティやメソッドを持つ複雑なオブジェクト
  • 長期間に渡って管理・共有されるデータ

5. 構造体を使うときの注意点

  • ボックス化(Boxing)が発生するとパフォーマンス低下の可能性あり→ object型やインターフェースに格納する際は注意
Position pos = new Position();
object obj = pos;  // Boxing発生
  • 参照が使えないため、ミューテーブルな設計は非推奨

参照が使えないため、ミューテーブルな設計は非推奨」というのは、構造体(struct)を「値型」として使うときの特性に起因します。


1. 背景:構造体は「値型」

構造体は値型なので、コピーされて渡されるという特徴があります。

つまり、「呼び出し先で中身を書き換えても、呼び出し元には影響しない」のです。


2. ミューテーブル(mutable)とは?

ミューテーブル(mutable)とは、「変更可能な状態を持つ」ことを指します。

たとえば、以下のような構造体:

struct Counter
{
    public int Value;

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

これは見た目は「変更できる」ように見えますが…


3. 参照が使えないとどうなる?

以下のように使用すると、期待通りに動かないことがあります:

Counter c = new Counter();
c.Increment();
Console.WriteLine(c.Value);  // 期待: 1、実際: 0

これはなぜか?


4. 原因:メソッド呼び出し時にコピーされる

c.Increment() の呼び出し時に、c は値型(構造体)なので、Increment() メソッド内ではコピーが操作されているのです。

つまり、以下と同じ意味になります:

var temp = c;  // コピー
temp.Value++;  // コピー側の変更
// 元の c は変わらない

5. 結果:構造体での「状態変更」は混乱を招く

構造体がミューテーブル(状態変更可能)だと、ユーザーが意図した通りに動かないことがあるため、非推奨とされるのです。


6. 解決策:構造体はイミュータブル(immutable)にする

以下のように、「状態変更しない」設計が推奨されます:

struct Position
{
    public float X { get; }
    public float Y { get; }

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

    public Position Move(float dx, float dy)
    {
        return new Position(X + dx, Y + dy);  // 新しい構造体を返す
    }
}

使用例:

Position p1 = new Position(1, 2);
Position p2 = p1.Move(1, 1);  // p1はそのまま、p2は新しい座標

まとめ

理由結論
値型はコピーされるメソッドでの変更が元に影響しない
意図せず「変更されない」ように見えるバグや混乱の元になる
そのため構造体は「変更不可設計」にするのが安全イミュータブル構造体推奨

このような背景から、構造体を「状態変更あり(ミューテーブル)」にするのは避けた方がよいというのが、C#の設計上のベストプラクティスです


6. 使い分けの目安(まとめ)

判断ポイント構造体(struct)クラス(class)
データのサイズが小さい
不変にしたい
状態が変わる
継承したい×
Unityで使う座標系◎(Vector3など)

7. よくある質問

Q. 構造体でもnewを使うのはなぜ?

A. 構造体はnewを使わなくても使えますが、newを使うことですべてのフィールドが0で初期化された状態になります。

Position p;       // 初期化されていない → 使用不可
Position p2 = new Position();  // OK(X=0, Y=0)

おわりに

構造体とクラスは似て非なるもの。それぞれの性質を理解し、適材適所で使い分けることがC#プログラミングの第一歩です。

とくにUnity開発では、構造体が内部でどう扱われるかを意識すると、パフォーマンス改善にも繋がります。


関連リンク


このブログは初学者でも理解できるよう、例を交えながら明確に構造体とクラスの違いを説明しました。

訪問数 14 回, 今日の訪問数 1回

C#,クラス,構造体

Posted by hidepon