C# 9 新特性——record的相关总结

C# 9 新特性——record的相关总结

引言

C# 9.0 版本带来了一些非常实用的新特性,其中最引人注目的莫过于record。这是一种新型的数据类型,专门用于表示“记录”数据,以及可以设置许多与属性相关的缺省值和模式匹配操作,使用起来非常方便。

本文主要讲解 C# 9 新特性中 record 的一些基础知识、语法、应用场景等内容。

C# 9.0 新特性 —— record

record 是 C#9.0 新加入的一种新类型,是 struct 的一种变种,主要用于表示不可变的数据。

record 和 struct 和 class 一样,都是定义一种新的数据集合,但它有一些特殊的属性:

  • record 可以声明为不可变的类型(只读)
  • record 的相等比较是值类型比较,而非引用类型比较。
  • record 的基本构造函数是带参数的,它自己有很多构造函数。
  • 在模式匹配(pattern matching)分支语句中,record 有额外的选项。

如果您在使用 .NET Core 3.1 和 C# 9.0,则需要将以下行添加到 csproj 文件中,以启用 C# 9.0。

<PropertyGroup>
  <LangVersion>9.0</LangVersion>
</PropertyGroup>

类 vs record

假设我们要编写一个应用程序,用于存储和显示一些长方形信息。我们可以定义 Rectangle 类,其中包含 Width 和 Height 属性。以下是该代码的示例:

public class Rectangle {
  public int Width { get; set; }
  public int Height { get; set; }

  public Rectangle(int width, int height) {
    Width = width;
    Height = height;
  }
}

此时,我们可以使用以下代码创建一个 Rectangle 对象:

Rectangle rect = new Rectangle(100, 150);

也可以更改 rect 的 Width 和 Height 属性:

rect.Width = 150;

但是,Rectangle 类有一个问题,那就是它是可变的,对象状态可以在代码中更改。换句话说,我们可以在程序的某个地方,修改 Width 和 Height 属性的值,这会导致 Rectangle 类的可变性,这在我们不希望修改某个对象状态时可能会导致问题。

为了解决这个问题,我们可以将 Rectangle 类转换为 record。

public record Rectangle(int Width, int Height);

这里我们定义了一个具有 Width 和 Height 两个属性的 record。这个属性不能更改,它是一个不可变的类型。这是因为我们仅仅可以从构造函数获取 record 的值,所以不允许使用默认的 setter 方法来更改 record 中的属性值。

定义 record 后,我们可以使用以下代码创建 Rectangle 对象。

Rectangle rect = new Rectangle(100, 150);

我们可以在代码的任何地方使用“新实例化”创建 Rectangle 对象,并且在声明后,它的属性名称和值都不能被修改。这意味着,rect 现在是一个不可变对象,在代码的任何其它地方,如果未经允许改变其状态,将不会影响到该对象。

record 类型语法介绍

record 类型的语法有五种。

1. 默认 record 类型

默认 record 类型类似如下代码。

public record Person {
  public string FirstName { get; init; }
  public string LastName { get; init; }
  public int Age { get; init; }
}

这里我们定义了一个名为 Person 的 record。Person 有 3 个属性:FirstName、LastName 和 Age。

1.1. init 属性

record 中的属性,可以使用 readonly 属性或可写的 init 属性设置只读(不可修改)状态。init 只能在构造函数中分配。

2. 可以增加一个 positional record 类型

位置记录的定义方式类似如下代码:

public record Person(string FirstName, string LastName, int Age);

3. 可以扩展 record 类型:

扩展 record 类型的方法类似如下

public record Person : ICloneable {
  public string FirstName { get; init; }
  public string LastName { get; init; }
  public int Age { get; init; }

  public object Clone() {
    return this.MemberwiseClone();
  }
}

这里,Person 继承了 ICloneable 接口,并实现了该接口的 Clone() 方法。

4. record 类型可以是泛型:

定义泛型 record 类型的方法如下:

public record Person<T>(string FirstName, string LastName, T Age);

5. record 类型可以定义私有构造函数和其他类成员:

public record Student {
  public string FirstName { get; init; }
  public string LastName { get; init; }
  public int Age { get; init; }

  private int _score;

  public Student(string firstName, string lastName, int age, int score) {
    FirstName = firstName;
    LastName = lastName;
    Age = age;
    _score = score; // 带有非默认的构造函数
  }
}

with表达式

使用 with 表达式来创建一个新的 record 对象,可以保留原始 record 对象的值,并根据需要更改一些属性。

以下是一个示例:

public record Person {
  public string FirstName { get; init; }
  public string LastName { get; init; }
  public int Age { get; init; }
}

Person person = new Person { FirstName = "Tony", LastName = "Stark", Age = 45 };

Person person2 = person with { LastName = "王" };

在这个例子中,我们定义了一个名为 Person 的 record 类型。我们创建了一个名为 person 的 Person 对象,FirstName、LastName 和 Age 分别被初始化为 "Tony"、"Stark" 和 45。

我们使用 with 表达式创建了另一个名为 person2 的 Person 对象,在这个新对象中我们仅更改了 LastName 属性。

记录变量 Person2 其余的值(即 FirstName 和 Age)来自 person。因此,person2 与 person 具有相同的值的属性,但有不同的 LastName 值。记住,这不会更改原始 record 的值,它只会创建一个新的 record 对象。

record struct

record struct 类似对结构体的定义,仅具有存储字段,而没有方法。

public record struct Foo {
    private int _value;

    public Foo(int value) {
        _value = value;
    }

    public int DoubleValue => _value * 2;
}

总结

Record 是一种非常有用的类型,在 C# 9.0 版本中,提供了一些很好的优化。使用 Record,我们主要可以得到以下两个好处。

其一,在读取你输入的对象时,如果其中的数据结构类似于 Record,那么就可以非常方便地为其设置默认值和构造函数,将同样类型的数据作为一个 Record 类型来处理。

其二,使用 Record 类型,我们可以实现一些非常高效的编程。这是因为 Record 可以通过引用传递而不是 clone。如上所述,不能更改 Record 中属性的值,而且引用传递将有助于避免发生不必要的克隆操作。因此,使用 Record 允许我们将一些应该不变的数据类型做成不可变的对象。

以上就是 C# 9 中 Record 的相关总结。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 9 新特性——record的相关总结 - Python技术站

(0)
上一篇 2023年6月7日
下一篇 2023年6月7日

相关文章

  • C#通过反射创建自定义泛型

    要通过反射在C#中创建自定义泛型,需要遵循以下步骤: 使用Type.MakeGenericType方法创建泛型类型的实例对象,并传递一个类型数组,该数组包含泛型类型所需的类型参数。 使用Activator.CreateInstance方法创建泛型类型对象的实例。 必要时使用反射获取泛型类型对象上的属性和方法,以使其在程序中正确运行。 以下是两个示例说明: 示…

    C# 2023年5月31日
    00
  • C#实现Ruby的负数索引器

    让我来详细讲解如何使用 C# 实现 Ruby 的负数索引器。 什么是 Ruby 的负数索引器 在 Ruby 中,我们可以使用负数索引器来从结尾开始访问数组元素。例如,一个包含 4 个元素的数组 arr,它们的索引分别为 0、1、2、3。如果我们想要访问最后一个元素,我们可以使用索引 -1,即 arr[-1]。类似的,如果我们想要访问倒数第二个元素,我们可以使…

    C# 2023年6月8日
    00
  • C# 获取系统DPI缩放比例以及分辨率大小

    一般方法 System.Windows.Forms.Screen类 // 获取当前主屏幕分辨率 int screenWidth = Screen.PrimaryScreen.Bounds.Width; int screenHeight = Screen.PrimaryScreen.Bounds.Height; // 获取指定屏幕分辨率 Screen seco…

    C# 2023年4月27日
    00
  • C#实现网络小程序的步骤详解

    下面是详细讲解“C#实现网络小程序的步骤详解”的完整攻略。 1. 确定需求和功能 在开始任何项目之前,我们必须明确需求和目标。首先,确定你的网络小程序需要完成的功能,包括功能模块、界面设计等,以此为基础,设计项目结构和流程。 2. 确定开发环境 C#可以在Windows平台上运行,因此您需要安装Visual Studio等适用的软件开发工具。您需要安装.NE…

    C# 2023年6月1日
    00
  • Java中前台往后台传递多个id参数的实例

    下面是关于Java中前台往后台传递多个id参数的攻略及示例说明。 前言 在Java后台开发中,经常需要前台传递多个id参数的情形。这时需要采用合适的方法将多个id参数传递到后台进行处理。本文介绍了两种常用的传递多个id参数的方法。 方法一: 传递多个字符串参数 适用范围:当需要在后台获取多个string类型参数时,可以采用该方法。 前台示例代码: <f…

    C# 2023年6月1日
    00
  • c#调用c++方法介绍,window api

    C#调用C++方法介绍 简介 C#是一种高级编程语言,而C++是一种中级编程语言,在底层处理方面有着突出的优势。将C++模块集成到C#应用程序中,可以利用C++的性能和底层优势来完成一些高性能任务。在实际应用中,使用C#调用C++模块的场景非常普遍,例如Windows API和某些组件库都是基于C++编写的,但是由于其底层特性和页面优化等方面,利用C#调用C…

    C# 2023年6月7日
    00
  • 使用C#获取网页HTML源码的例子

    下面是使用C#获取网页HTML源码的例子的完整攻略。 1. 了解HttpWebRequest和HttpWebResponse 在使用C#获取网页HTML源码之前,需要先了解两个类:HttpWebRequest和HttpWebResponse。HttpWebRequest是用于向服务器发送Web请求的类,HttpWebResponse是用于接收服务器返回Web…

    C# 2023年6月7日
    00
  • ASP.NET数据库存取图片的方法

    ASP.NET 是一个基于 .NET 框架的 Web 应用程序开发平台,它可以使用多种方式存储图片,包括将图片存储在文件系统中,或者将它们存储在数据库中。 以下是在 ASP.NET 中存储和访问图片的两种常见方法: 方法1:将图片存储在文件系统中 将图片存储在文件系统中是最常见的方法之一,主要包括两个步骤:上传图片和显示图片。 1.1上传图片 上传图片可以使…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部