C#9でレコード型を使用するには?

C#9でレコード型を使用するには?

レコードを使いましたか?

最后更新 2021/07/10 22:27
沙漠尽头的狼
预计阅读 7 分钟
分类
.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

砂漠の果ての狼

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

不変性はオブジェクトをスレッドセーフにし、メモリ管理の改善に役立ちます。また、コードを読みやすく、メンテナンスしやすくします。不変オブジェクトとは、一度作成すると変更できないオブジェクトとして定義されます。したがって、不変オブジェクトは本質的にスレッドセーフであり、競合する条件の影響を受けません。

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

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

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

Visual Studioでのコンソール·アプリケーション·プロジェクトの作成

まず、Visual Studioで. NET Coreコンソール·アプリケーション·プロジェクトを作成します。システムにVisual Studio 2019がインストールされていると仮定すると、以下の手順に従ってVisual Studioで新しい. NET Coreコンソールアプリケーションプロジェクトを作成します。

  1. Visual Studio IDEを起動します。
  2. “Create new project.”をクリックします。
  3. Create new projectウィンドウで、表示されるテンプレートのリストからConsole App. NET Coreを選択します。
  4. 次へクリック。
  5. 次に表示される“Configure your new project”ウィンドウで、新規プロジェクトの名前と場所を指定します。
  6. Creationをクリック。

これらの手順に従うと、Visual Studio 2019で新しい. NET Coreコンソールアプリケーションプロジェクトが作成されます。この項目は、この記事の後半で使用します。

C#9でのinit-onlyプロパティの使用

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

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

次のコードスニペットを使用して、DbMetadataクラスのインスタンスを作成し、そのプロパティを初期化できます。

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

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

dbMetadata.DbType = "SQL Server";

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; }
}

次のコードスニペットを使用して、Personクラスのインスタンスを作成し、そのプロパティを初期化できます。

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

C#9でのwith式の使用

如果某些属性具有相同的值,您可能经常希望从另一个对象创建一个对象。但是,记录类型的 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" };

C#9のレコード型継承

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

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

C#9の位置レコード

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

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

C#9でレコードインスタンスが等しいかどうかをチェックする

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

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

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

次のコードスニペットは、DbMetadataレコードタイプの2つのインスタンスを作成する方法を示しています。

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"
};

次の2つのステートメントは、コンソールウィンドウに“true”を表示します。

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() 方法的重载。这些方法是隐式生成的,您无需重新实现它们。

C#でのEqualsメソッドのチェック

您可以检查是否已隐式生成了 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);
}

コードをコンパイルすると、コンパイラーは以下のメッセージでエラーをマークします。

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

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

Keep Exploring

延伸阅读

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

バージョン別の. NETサポート状況(250 7 0 7更新)

仮想マシンとテストマシンを使用して、各バージョンのオペレーティングシステムの. NETサポートをテストします。オペレーティングシステムのインストール後、対応するランタイムを測定し、スターダストエージェントをパスとして実行できます。

继续阅读
同分类 / 同标签 2026/02/07

AOTの使用経験

プロジェクトの最初から、新しい機能が追加されたり、新しい構文が使用されたりするたびに、AOTリリーステストを行うという良い習慣を身につける必要があります。

继续阅读