基礎から学ぶC#入門 90日コース | 継承・抽象化・インターフェース - Day 48:record・struct

C# 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 48 のゴールと全体像

Day 48 のテーマは struct record、そしてクラスとの違いです。

キーワードはこの3つです。

  • struct
  • record
  • クラスとの違い

ここまで「クラス」を中心にオブジェクト指向を学んできましたが、 C# には「クラス以外の型」も存在します。 今日はそれらを、実際の使いどころに焦点を当てて見ていきます。

クラスとの違いをざっくりイメージする

まずは「参照型」と「値型」という違い

C# では、

  • クラス(class → 参照型(reference type)
  • 構造体(struct → 値型(value type)

という大きな違いがあります。

ざっくり言うと、

  • クラス:「オブジェクトへの参照」を扱う
  • struct:「中身そのもの」を扱う

というイメージです。

record は少し特殊で、

  • record class(参照型)
  • record struct(値型)

の両方がありますが、 入門ではまず 「データを表すのに便利なクラスの仲間」として捉えるとよいです。

struct(構造体)とは何か

「小さな値のまとまり」を表すのに向いた型

struct は、

「いくつかの値をひとまとめにしたいけれど、 オブジェクトというほど大げさではない」

という場面に向いた型です。

たとえば、座標やサイズなどの「小さなデータのまとまり」によく使われます。

シンプルな struct の例:Point

// 2次元の座標を表す構造体
struct Point
{
    public int X; // X座標
    public int Y; // Y座標

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

    // 座標を表示するメソッド
    public void Show()
    {
        Console.WriteLine($"({X}, {Y})");
    }
}
C#

使う側はこうなります。

class Program
{
    static void Main(string[] args)
    {
        // 構造体のインスタンスを作成
        Point p1 = new Point(10, 20);
        p1.Show(); // (10, 20)

        Console.ReadLine();
    }
}
C#

ここまではクラスとあまり変わらないように見えますが、 値型であることが大きな違いを生みます。

struct の「値型らしさ」を体験する

コピーされるのは「参照」ではなく「中身」

クラスの場合、

class Person
{
    public string Name;
}
C#
Person a = new Person { Name = "Alice" };
Person b = a; // 参照をコピー

b.Name = "Bob";

Console.WriteLine(a.Name); // Bob(同じオブジェクトを指している)
C#

というふうに、 「参照」をコピーしているだけなので、 中身は共有されます。

一方、struct の場合はこうです。

struct Point
{
    public int X;
    public int Y;
}
C#
Point p1 = new Point { X = 10, Y = 20 };
Point p2 = p1; // 中身がコピーされる

p2.X = 99;

Console.WriteLine(p1.X); // 10(p1 と p2 は別物)
Console.WriteLine(p2.X); // 99
C#

重要ポイント:

  • struct は「値型」なので、代入すると 中身がコピーされる
  • クラスは「参照型」なので、代入すると 参照がコピーされる

この違いが、 「どんな場面で struct を使うべきか」に関わってきます。

struct を使うのに向いている場面

1. 小さくて、頻繁にコピーされるデータ

  • 座標(Point
  • サイズ(Size
  • 色(Color

など、 「小さな値のまとまり」で、 コピーされることが多いものは struct に向いています。

2. 「同じオブジェクトを共有する」より「値そのもの」を扱いたいとき

  • 「この関数に渡すときは、値をコピーして渡したい」
  • 「別の変数に代入しても、元の値は変わってほしくない」

という場面では、 struct の「値型らしさ」が役立ちます。

record とは何か

「データを表すクラス」を簡潔に書くための仕組み

record は、

「データを表すクラスを、 できるだけ少ないコードで、 しかも比較や表示もしやすく書きたい」

というニーズに応えるための機能です。

特に、

  • 「プロパティだけを持つシンプルなデータクラス」
  • 「値の等価性(中身が同じかどうか)を簡単に扱いたい」

といった場面で活躍します。

シンプルな record の例:User

// ユーザー情報を表すレコードクラス
public record User(string Name, int Age);
C#

たったこれだけで、

  • NameAge のプロパティを持つ
  • コンストラクタが自動で定義される
  • ToString() がいい感じに実装される
  • Equals / GetHashCode が「中身の値」で比較するように実装される

という、 「データクラスとして欲しい機能」が一気に手に入ります。

record の使い方を見てみる

インスタンスを作ってみる

class Program
{
    static void Main(string[] args)
    {
        User u1 = new User("山田", 30);
        User u2 = new User("山田", 30);
        User u3 = new User("佐藤", 25);

        Console.WriteLine(u1); // User { Name = 山田, Age = 30 }

        // 中身が同じかどうかの比較
        Console.WriteLine(u1 == u2); // true
        Console.WriteLine(u1 == u3); // false

        Console.ReadLine();
    }
}
C#

ここで注目してほしいのは、

  • Console.WriteLine(u1); の出力が、 「プロパティ名と値」を含んだ分かりやすい文字列になっていること
  • u1 == u2「参照が同じか」ではなく「中身が同じか」で比較されていること

です。

通常のクラスだと、

class UserClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}
C#
UserClass c1 = new UserClass { Name = "山田", Age = 30 };
UserClass c2 = new UserClass { Name = "山田", Age = 30 };

Console.WriteLine(c1 == c2); // false(参照が違うので)
C#

となり、 「中身が同じかどうか」を自分で実装しないといけません。

record は、 そのあたりを 「データクラスとしての便利機能」としてまとめて提供してくれるイメージです。

record とクラスの違いを整理する

クラス(通常の class)

  • 参照型
  • == は「参照が同じかどうか」を比較する(デフォルト)
  • ToString() はクラス名だけになることが多い
  • データクラスとして使う場合、
    • コンストラクタ
    • プロパティ
    • Equals / GetHashCode
    • ToString() を自分で書くことが多い

record(record class)

  • 参照型(record class の場合)
  • == は「中身の値が同じかどうか」を比較する
  • ToString() は「プロパティ名と値」を含んだ分かりやすい文字列になる
  • データクラスとして使う場合に必要な機能が、 かなり自動で用意される

重要ポイント:

  • record は「データを表すクラス」を簡潔に書くための仕組み
  • クラスとの違いは「等価性の扱い」と「便利な自動実装」にある

struct・record・class の違いをまとめてイメージする

ざっくり3者比較

  • class
    • 参照型
    • オブジェクト指向の中心
    • 状態+振る舞いを持つ「普通のオブジェクト」
  • struct
    • 値型
    • 小さな値のまとまりに向いている
    • コピーすると中身が複製される
  • record
    • 「データを表すクラス」を簡潔に書くための仕組み
    • 中身の値で等価性を比較する
    • データクラスとしての便利機能が自動で付いてくる

入門段階では、

「普段は class を使う。 小さな値のまとまりなら struct。 データを表すだけなら record。」

くらいの感覚で捉えておくと、 実務でも迷いにくくなります。

struct・record の基本テンプレート

struct のテンプレート

// 2Dサイズを表す構造体
struct Size
{
    public int Width;
    public int Height;

    public Size(int width, int height)
    {
        Width = width;
        Height = height;
    }

    public void Show()
    {
        Console.WriteLine($"幅: {Width}, 高さ: {Height}");
    }
}
C#

record のテンプレート

// 商品情報を表すレコード
public record Product(string Id, string Name, decimal Price);
C#
class Program
{
    static void Main(string[] args)
    {
        // struct の利用
        Size s1 = new Size(100, 200);
        Size s2 = s1; // 中身がコピーされる
        s2.Width = 300;

        s1.Show(); // 幅: 100, 高さ: 200
        s2.Show(); // 幅: 300, 高さ: 200

        // record の利用
        Product p1 = new Product("P001", "ノートPC", 120000m);
        Product p2 = new Product("P001", "ノートPC", 120000m);

        Console.WriteLine(p1);          // Product { Id = P001, Name = ノートPC, Price = 120000 }
        Console.WriteLine(p1 == p2);    // true(中身が同じなので)

        Console.ReadLine();
    }
}
C#

Day 48 のまとめ

Day 48 では、

  • struct → 値型として「小さな値のまとまり」を表す型
  • record → 「データを表すクラス」を簡潔に書き、 中身の値で等価性を扱えるようにする仕組み
  • クラスとの違い → 参照型/値型、等価性の扱い、便利な自動実装の有無

を、座標・サイズ・ユーザー・商品などの例を通して学びました。

実務では、

  • 「普通のオブジェクト」→ class
  • 「小さな値のまとまり」→ struct
  • 「データを表すだけの型」→ record

という使い分けができると、 コードの意図がぐっと伝わりやすくなります。

ぜひ、

  • 自分で struct を1つ作って「値型らしさ(コピーのされ方)」を試してみる
  • record で小さなデータクラスを作って、==ToString() の挙動を確認してみる

という小さな練習を通して、 struct と record を 「ただのキーワード」ではなく、 設計を少しだけ気持ちよくしてくれる道具として、 少しずつ体に馴染ませていってください。

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