How to use the record type in C#9?

How to use the record type in C#9?

Have you ever used record?

最后更新 7/10/2021 10:27 PM
沙漠尽头的狼
预计阅读 8 分钟
分类
.NET
标签
.NET C# Record

原文链接:https://www.infoworld.com/article/3607372/how-to-work-with-record-types-in-csharp-9.html

原文标题:How to work with record types in C# 9

The Wolf at the End of the Desert

利用 C# 9 中的record类型来构建不可变类型和线程安全对象。

Immutability makes your objects thread-safe and helps improve memory management. It also makes your code more readable and easier to maintain. Immutable objects are defined as objects that cannot be changed once created. Therefore, immutable objects are inherently thread-safe and are not affected by race conditions.

直到最近,C# 还不支持开箱即用的不可变性。C# 9 通过新的 init-only 属性和record类型引入了对不可变性的支持。仅init-only属性可用于使对象的各个属性不可变,而record可用于使整个对象不可变。

因为不可变对象不会改变它们的状态,所以在多线程和数据传输对象等许多用例中,不可变性是一个理想的特性。本文讨论了我们如何在 C# 9 中使用 init-only 属性和record类型。

要使用本文中提供的代码示例,您应该在系统中安装 Visual Studio 2019。如果您还没有安装,可以在此处下载 Visual Studio 2019

Create a console application project in Visual Studio

First, let's create a. NET Core console application project in Visual Studio. Assuming you have Visual Studio 2019 installed on your system, follow the steps outlined below to create a new. NET Core console application project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click "Create new project."
  3. In the Create new project window, select "Console App (. NET Core)" from the list of templates displayed.
  4. Click Next.
  5. In the "Configure your new project" window that appears next, specify the name and location of the new project.
  6. Click Create.

Following these steps will create a new. NET Core console application project in Visual Studio 2019. We will use this project in subsequent sections of this article.

Using the init-only attribute in C#9

init-only属性是那些只能在对象初始化时赋值的属性。请参阅以下包含 init-only 属性的类。

public class DbMetadata
{
    public string DbName { get; init; }
    public string DbType { get; init; }
}

You can use the following code fragment to create an instance of the DbMetadata class and initialize its properties.

DbMetadata dbMetadata = new DbMetadata()
{
      DbName = "Test",
      DbType = "Oracle"
};

请注意,对 init-only 字段的后续分配是非法的。因此,以下语句将无法编译。

dbMetadata.DbType = "SQL Server";

Using the record type in C#9

C# 9 中的record类型是仅具有只读属性的轻量级、不可变数据类型(或轻量级类)。因为record类型是不可变的,所以它是线程安全的,并且在创建后不能改变或更改。您只能在构造函数中初始化record类型。

您可以使用 record 关键字声明record,如下面的代码片段所示。

public record Person
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Address { get; set; }
  public string City { get; set; }
  public string Country { get; set; }
}

请注意,仅将类型标记为record(如前面的代码片段所示)本身不会为您提供不可变性。要为您的record类型提供不可变性,您必须使用 init 属性,如下面的代码片段所示。

public record Person
{
  public string FirstName { get; init; }
  public string LastName { get; init; }
  public string Address { get; init; }
  public string City { get; init; }
  public string Country { get; init; }
}

You can use the following code fragment to create an instance of the Person class and initialize its properties.

var person = new Person
{
  FirstName = "Joydip",
  LastName = "Kanjilal",
  Address = "192/79 Stafford Hills",
  City = "Hyderabad",
  Country = "India"
};

Using the with expression in C#9

如果某些属性具有相同的值,您可能经常希望从另一个对象创建一个对象。但是,记录类型的 init-only 属性会阻止这种情况。例如,以下代码片段将无法编译,因为默认情况下名为 Person 的record类型的所有属性都是 init-only

var newPerson = person;
newPerson.Address = "112 Stafford Hills";
newPerson.City = "Bangalore";

幸运的是,有一个解决方法——with 关键字。通过指定属性值的更改,您可以利用 with 关键字从另一个record类型创建一个实例。以下代码片段说明了如何实现这一点。

var newPerson = person with
            { Address = "112 Stafford Hills", City = "Bangalore" };

Inheritance of record type in C#9

record类型支持继承。也就是说,您可以从现有record类型创建新record类型并添加新属性。以下代码片段说明了如何通过扩展现有record类型来创建新record类型。

public record Employee : Person
{
   public int Id { get; init; }
   public double Salary { get; init; }
}

Position in C#9 record

默认情况下,使用位置参数创建的record类型实例是不可变的。换句话说,您可以通过使用构造函数参数传递有序的参数列表来创建record类型的不可变实例,如下面给出的代码片段所示。

var person = new Person("Joydip", "Kanjilal", "192/79 Stafford Hills", "Hyderabad", "India");

Check whether record instances are equal in C#9

在 C# 中检查类的两个实例是否相等时,比较基于这些对象的引用(身份)。但是,如果您检查record类型的两个实例是否相等,则比较基于record类型的实例中的值。

以下代码片段说明了一个名为 DbMetadata 的record类型,它由两个字符串属性组成。

public record DbMetadata
{
   public string DbName { get; init; }
   public string DbType { get; init; }
}

The following code fragment shows how to create two instances of the DbMetadata record type.

DbMetadata dbMetadata1 = new DbMetadata()
{
   DbName = "Test",
   DbType = "Oracle"
};
DbMetadata dbMetadata2 = new DbMetadata()
{
   DbName = "Test",
   DbType = "SQL Server"
};

您可以使用 Equals 方法检查相等性。以下两个语句将在控制台窗口中显示“false”。

Console.WriteLine(dbMetadata1.Equals(dbMetadata2));
Console.WriteLine(dbMetadata2.Equals(dbMetadata1));

考虑以下创建 DbMetadata record类型的第三个实例的代码片段。请注意,实例 dbMetadata1 和 dbMetadata3 包含相同的值。

DbMetadata dbMetadata3 = new DbMetadata()
{
   DbName = "Test",
   DbType = "Oracle"
};

The following two statements will display "true" in the console window.

Console.WriteLine(dbMetadata1.Equals(dbMetadata3));
Console.WriteLine(dbMetadata3.Equals(dbMetadata1));

尽管record类型是引用类型,但 C# 9 提供了合成方法来遵循基于值的相等语义。编译器为您的record类型生成以下方法以强制实施基于值的语义:

  • Object.Equals(Object) 方法的重载
  • 接受record类型作为其参数的虚拟 Equals 方法
  • Object.GetHashCode() 方法的重载
  • 两个相等运算符的方法,即 == 运算符 和 != 运算符
  • record类型实现 System.IEquatable<T>

此外,记录类型提供了 Object.ToString() 方法的重载。这些方法是隐式生成的,您无需重新实现它们。

Check the Equals method in C#

您可以检查是否已隐式生成了 Equals 方法。为此,请在 DbMetadata 记录中添加一个 Equals 方法,如下所示。

public record DbMetadata
{
    public string DbName { get; init; }
    public string DbType { get; init; }
    public override bool Equals(object obj) =>
    obj is DbMetadata dbMetadata && Equals(dbMetadata);
}

When you compile code, the compiler marks errors with the following message:

Type 'DbMetadata' already defines a member called 'Equals' with the same parameter types

尽管record类型是一个类,但 record 关键字提供了额外的类似值类型的行为和语义,使record与类不同。record本身是一种引用类型,但它使用自己的内置相等性检查——相等性是通过值而不是引用来检查的。最后,请注意record可以是可变的,但它们主要是为不变性而设计的。

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读