C# 9.0 以降では「レコード型(record)」が導入されました。レコード型は主に「データを保持するための型」として設計されており、イミュータブル(変更不可)なオブジェクトや値の比較を簡潔に扱えるのが特徴です。本記事ではレコード型の基本と、従来のクラスや構造体との違いを解説します。
レコード型とは?
レコード型は、クラスや構造体のようにデータをまとめる仕組みですが、データ中心の設計に特化しています。特に次の点が特徴です。
- イミュータブルなデータモデルを簡単に定義できる
- 値の比較が自動で実装される(値比較)
- 簡潔な構文で定義できる
基本的な定義方法
public record Person(string Name, int Age);
class Program
{
static void Main()
{
var p1 = new Person("Taro", 20);
var p2 = new Person("Taro", 20);
Console.WriteLine(p1 == p2); // True(値が同じなら等しい)
}
}
クラスではデフォルトで「参照の一致」が比較されますが、レコード型では「値の一致」で比較される点が大きな違いです。
イミュータブルなデータ
レコード型は通常、プロパティが init
アクセサを持つため、オブジェクト生成時にのみ値を設定できます。これにより、生成後に値を変更できない安全なデータ構造を作成できます。
public record Product
{
public string Name { get; init; }
public int Price { get; init; }
}
class Program
{
static void Main()
{
var p = new Product { Name = "Book", Price = 1000 };
// p.Price = 2000; // エラー: init プロパティは変更できない
}
}
with式によるコピー
レコード型は with
式を使って、一部の値を変更した新しいインスタンスを簡単に作成できます。
var p1 = new Person("Hanako", 25);
var p2 = p1 with { Age = 26 };
Console.WriteLine(p1); // Person { Name = Hanako, Age = 25 }
Console.WriteLine(p2); // Person { Name = Hanako, Age = 26 }
元のオブジェクトを保持したまま、新しいオブジェクトを効率よく作成できます。
クラスとの違い
- クラス: デフォルトでは参照型で、等価比較は参照の一致
- レコード型: デフォルトで値比較を実装し、データモデルに適する
クラスでも値比較を実装できますが、Equals()
や GetHashCode()
を自分で書く必要があります。レコード型はこれを自動生成してくれる点で便利です。
構造体(struct)との違い
- 構造体: 値型(スタックに割り当てられることが多い)、小規模データに適する
- レコード型: クラスベース(参照型)が基本。ただし
record struct
として値型レコードも定義可能
public record struct Point(int X, int Y);
var p1 = new Point(1, 2);
var p2 = new Point(1, 2);
Console.WriteLine(p1 == p2); // True(値が同じなら等しい)
まとめ
C# のレコード型は「データモデルの表現」を簡潔かつ安全にするための仕組みです。
- 値比較やイミュータブル設計が標準でサポートされる
with
式で簡単にコピー&変更が可能- クラスや構造体よりも「データ中心の設計」に適している
DTO(データ転送オブジェクト)や設定値オブジェクトなど、値の比較や変更不可が求められるケースで活用するのがベストプラクティスです。