C# 中的 记录 是 类 或 结构,提供用于处理数据模型的特殊语法和行为。
record
修饰符指示编译器合成对主要用于存储数据的类型有用的成员。 这些成员包括支持值相等的 ToString() 和成员的重载。
何时使用记录
在下列情况下,请考虑使用记录而不是类或结构:
- 你想要定义一个数据模型,该模型依赖于 值相等。
- 你想要定义对象不可变的类型。
值相等性
对于记录,值相等意味着,如果类型匹配且所有属性和字段值相等,则记录类型的两个变量相等。 对于其他引用类型(如类),默认相等性指的是 引用相等性,除非已经实现了 值相等性。 也就是说,如果类类型的两个变量引用同一对象,则它们相等。 确定两个记录实例相等性的方法和运算符使用值相等性。
并非所有数据模型都能很好地处理值相等性。 例如,Entity Framework Core 依赖引用相等性,来确保它对概念上是一个实体的实体类型只使用一个实例。 因此,记录类型不适合在 Entity Framework Core 中用作实体类型。
不可变性
不可变类型可阻止在实例化对象后更改对象的任何属性或字段值。 如果需要类型是线程安全的,或者依赖于哈希表中剩余的哈希代码,则不可变性非常有用。 记录提供用于创建和使用不可变类型的简洁语法。
不可变性不适用于所有数据方案。 例如,Entity Framework Core不支持使用不可变实体类型进行更新。
记录与类和结构有何不同
声明和实例化类或结构时使用的语法与操作记录时的相同。 只需将 class
关键字替换为 record
,或使用 record struct
而不是 struct
。 同样,记录类也支持表示继承关系的相同语法。 记录与类的区别如下所示:
- 可以在主构造函数 中使用 位置参数 来创建和实例化具有不可变属性的类型。
- 在类中指示引用相等性或不相等的方法和运算符(例如 Object.Equals(Object) 和
==
)在记录中指示值相等性或不相等。 - 可以使用
with
表达式 创建具有所选属性中新值的不可变对象的副本。 - 记录的
ToString
方法创建一个格式化字符串,该字符串显示对象的类型名称和所有公共属性的名称和值。 - 记录可从另一个记录继承。 记录不能从类继承,而类不能从记录继承。
记录结构与结构的不同之处是,编译器合成了方法来确定相等性和 ToString
。 编译器为带位置属性的记录结构合成 Deconstruct
方法。
编译器为 record class
中的每个主构造函数参数合成一个公共仅初始化属性。 在 record struct
中,编译器合成公共读写属性。 编译器不会在不包含 class
修饰符的 struct
和 record
类型中创建主构造函数参数的属性。
例子
以下示例定义使用位置参数声明和实例化记录的公共记录。 然后输出类型名称和属性值:
public record Person(string FirstName, string LastName);
public static class Program
{
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 class Program
{
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
表达式复制不可变对象并更改其中一个属性:
public record Person(string FirstName, string LastName)
{
public required string[] PhoneNumbers { get; init; }
}
public class Program
{
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# 语法和用法的明确来源。