C# のレコード型の概要
C# のレコードとは、データ モデルを操作するための特殊な構文と動作を提供するクラスまたは構造体です。
レコードを使用する場面
次のシナリオでは、クラスまたは構造体の代わりにレコードを使用することを検討してください。
- 値の等価性に依存するデータ モデルを定義する。
- オブジェクトが不変となる型を定義する。
値の等価性
レコードにおける値の等価性とは、型が一致し、かつプロパティおよびフィールドの値がすべて一致する場合にレコード型の 2 つの変数が等しいことを意味します。 クラスなどの他の参照型における等価性とは、参照の等価性を意味します。 つまり、クラス型の 2 つの変数は、同じオブジェクトを参照する場合、等しいことになります。 2 つのレコード インスタンスが等しいかどうかを判断するメソッドと演算子では、値の等価性が使用されます。
すべてのデータ モデルが値の等価性に適しているわけではありません。 たとえば、Entity Framework Core では、概念的に 1 つのエンティティであるものに対して、エンティティ型の 1 つのインスタンスだけが確実に使用されるようにするために、参照の等価性に依存します。 このため、レコード型は Entity Framework Core でエンティティ型として使用するのに適していません。
不変性
不変型とは、オブジェクトがインスタンス化された後にそのプロパティまたはフィールドの値を変更できないようにするためのものです。 不変性は、型をスレッドセーフにする必要がある場合またはハッシュ テーブル内で変化のないハッシュ コードに依存している場合に役立ちます。 レコードには、不変型を作成および操作するための簡潔な構文が用意されています。
不変性は、すべてのデータ シナリオに適しているわけではありません。 たとえば、Entity Framework Core では、不変のエンティティ型を使用した更新がサポートされていません。
レコードと、クラスおよび構造体との違い
クラスまたは構造体を宣言およびインスタンス化するのと同じ構文をレコードでも使用できます。 class
キーワードを record
に置き換えたり、struct
ではなく record struct
を使用したりするだけです。 同様に、継承関係を表す場合も同じ構文がレコード クラスによってサポートされています。 レコードは次の点がクラスとは異なります。
- 位置指定パラメーターを使用して、不変プロパティを持つ型を作成してインスタンス化することができます。
- クラスで参照の等価性または非等価性を示すメソッドと演算子 (Object.Equals(Object) や
==
など) は、レコードではObject.Equals(Object)を示します。 - 式を使用すれば、選択したプロパティに新しい値を指定して、不変オブジェクトのコピーを作成することができます。
- レコードの
ToString
メソッドを使用すると、オブジェクトの型名とそのすべてのパブリック プロパティの名前および値を示す書式設定された文字列が作成されます。 - レコードは、別のレコードから継承できます。 レコードはクラスから継承できません。また、クラスはレコードから継承できません。
レコード構造体は、コンパイラによって同等のメソッドおよび ToString
が合成されるという点で構造体とは異なります。 位置指定のレコード構造体の場合、コンパイラによって Deconstruct
メソッドが合成されます。
例
次の例では、位置指定パラメーターを使用してレコードを宣言およびインスタンス化するパブリック レコードを定義します。 次に、型名とプロパティ値を出力します。
public record Person(string FirstName, string LastName);
public static void Main()
{
Person person = new("Nancy", "Davolio");
Console.WriteLine(person);
// output: Person { FirstName = Nancy, LastName = Davolio }
}
次の例では、レコードでの値の等価性を示します。
public record Person(string FirstName, string LastName, string[] PhoneNumbers);
public static void Main()
{
var phoneNumbers = new string[2];
Person person1 = new("Nancy", "Davolio", phoneNumbers);
Person person2 = new("Nancy", "Davolio", phoneNumbers);
Console.WriteLine(person1 == person2); // output: True
person1.PhoneNumbers[0] = "555-1234";
Console.WriteLine(person1 == person2); // output: True
Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
}
次の例では、with
式を使用して、不変オブジェクトをコピーし、プロパティの 1 つを変更する方法を示します。
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; }
}
public static void Main()
{
Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
Console.WriteLine(person1);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Person person2 = person1 with { FirstName = "John" };
Console.WriteLine(person2);
// output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False
person2 = person1 with { PhoneNumbers = new string[1] };
Console.WriteLine(person2);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False
person2 = person1 with { };
Console.WriteLine(person1 == person2); // output: True
}
詳細については、「レコード (C# リファレンス)」を参照してください。
C# 言語仕様
詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。