百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

C# 9.0新特性Record介绍

bigegpt 2024-09-22 00:39 3 浏览

. net 5支持c# 9.0,c# 9.0为c#语言添加了Record 特性

Record 类型

C# 9.0 引入了Record类型,这是一种引用类型,它提供合成方法来提供值语义,从而实现相等性。 默认情况下,记录是不可变的。

使用Record类型可在 .NET 中轻松创建不可变的引用类型。 以前,.NET 类型主要分为引用类型(包括类和匿名类型)和值类型(包括结构和元组)。 虽然建议使用不可变的值类型,但可变的值类型通常不会引入错误。 值类型变量可保存值,因此在将值类型传递给方法时,会对原始数据的副本进行更改。

不可变的引用类型也有许多优点。 这些优点在使用共享数据的并发程序中更为明显。 遗憾的是,C# 强制编写大量额外的代码来创建不可变的引用类型。Record为不可变的引用类型提供类型声明,该引用类型使用值语义实现相等性。 如果用于实现相等性的合成方法的属性和哈希代码的属性都相等,则认为两条记录相等。

public record Person

{

public string LastName { get; }

public string FirstName { get; }


public Person(string first, string last) => (FirstName, LastName) = (first, last);

}


Record定义会创建一个包含两个只读属性(FirstName 和 LastName)的 Person 类型。 Person 类型是引用类型。 如果查看 IL,它就是一个类。 它是不可变的,因为在创建它后,无法修改任何属性。 定义记录类型时,编译器会自动合成其他几种方法:Eques,GetHashCode,Copy,Clone,ToString等

记录支持继承。 可声明派生自 Person 的新记录,如下所示:


public record Teacher : Person

{

public string Subject { get; }


public Teacher(string first, string last, string sub)

: base(first, last) => Subject = sub;

}

还可密封记录以防止进一步派生:

public sealed record Student : Person

{

public int Level { get; }


public Student(string first, string last, int level) : base(first, last) => Level = level;

}

编译器会合成上述方法的不同版本。 方法签名取决于记录类型是否密封以及直接基类是否为对象。 记录应具有以下功能:

  • 相等性是基于值的,包括检查类型是否匹配。 例如,即使两条记录的名称相同,Student 也不能等于 Person。
  • Records具有为你生成的一致的字符串表示形式。
  • Records支持Copy构造。 正确的Copy构造必须包括继承层次结构和开发人员添加的属性。
  • 可通过修改Copy记录。 这些Copy和修改操作支持非破坏性转变。

除了熟悉的 Equals 重载、operator == 和 operator != 外,编译器还会合成新的 EqualityContract 属性。 该属性返回与记录类型匹配的 Type 对象。 如果基类型为 object,则属性为 virtual。 如果基类型是其他记录类型,则属性为 override。 如果记录类型为 sealed,则属性为 sealed。 合成的 GetHashCode 使用基类型和记录类型中声明的所有属性和字段中的 GetHashCode。 这些合成方法在整个继承层次结构中强制执行基于值的相等性。 这意味着,绝不会将 Student 视为与同名的 Person 相等。 两条记录的类型必须匹配,而且记录类型之间共享的所有属性也必须相等。

记录还具有合成的构造函数和用于创建副本的“克隆”方法。 合成的构造函数具有记录类型的一个参数。 该函数会为记录的所有属性生成具有相同值的新记录。 如果记录是密封的,则此构造函数是专用函数;否则它将受到保护。 合成的“克隆”方法支持用于记录层次结构的副本构造。 “克隆”一词用引号引起来,因为实际名称是编译器生成的。 无法在记录类型中创建名为 Clone 的方法。 合成的“克隆”方法返回使用虚拟调度复制的记录类型。 编译器根据 record 上的访问修饰符为“克隆”方法添加不同的修饰符:

  • 如果记录类型为 abstract,则“克隆”方法也为 abstract。 如果基类型不是 object,则方法也是 override。
  • 当基类型为 object 时,对于不是 abstract 的记录类型:
    • 如果记录为 sealed,则不向“克隆”方法添加其他修饰符(这意味着它不是 virtual)。
    • 如果记录不是 sealed,则“克隆”方法为 virtual。
  • 当基类型不是 object 时,对于不是 abstract 的记录类型:
    • 如果记录是 sealed,则“克隆”方法也是 sealed。
    • 如果记录不是 sealed,则“克隆”方法为 override。


所有这些规则的结果都是,跨记录类型的任何层次结构一致地实现了相等性。 如果两条记录的属性相等且类型相同,则它们彼此相等,如下例所示:

var person = new Person("Bill", "Wagner");

var student = new Student("Bill", "Wagner", 11);


Console.WriteLine(student == person); // false


编译器合成了两种支持打印输出的方法:ToString() 替代和 PrintMembers。 PrintMembers 采用 System.Text.StringBuilder 作为其参数。 它对记录类型中的所有属性追加一个用逗号分隔的属性名称和值的列表。 PrintMembers 会调用派生自其他记录的任何记录的基本实现。 ToString() 替代会返回由 PrintMembers 生成的字符串,并将其括在 { 和 } 内。 例如,Student 的 ToString() 方法返回一个 string,类似于以下代码:


"Student { LastName = Wagner, FirstName = Bill, Level = 11 }"

截至目前显示的示例都使用传统语法声明属性。 还有一种更简洁的格式,称为“位置记录”。 下面是先前定义为位置记录的 3 种记录类型:

public record Person(string FirstName, string LastName);


public record Teacher(string FirstName, string LastName,

string Subject)

: Person(FirstName, LastName);


public sealed record Student(string FirstName,

string LastName, int Level)

: Person(FirstName, LastName);

这些声明创建的功能与早期版本相同(以下部分介绍了几项额外的功能)。 这些声明以分号而不是方括号结尾,因为这些记录没有添加其他方法。 可添加正文,还可包括其他任何方法:

public record Pet(string Name)

{

public void ShredTheFurniture() =>

Console.WriteLine("Shredding furniture");

}


public record Dog(string Name) : Pet(Name)

{

public void WagTail() =>

Console.WriteLine("It's tail wagging time");


public override string ToString()

{

StringBuilder s = new();

base.PrintMembers(s);

return #34;{s.ToString()} is a dog";

}

}

编译器为位置记录生成 Deconstruct 方法。 Deconstruct 方法的参数与记录类型中所有公共属性的名称匹配。 Deconstruct 方法可用于将记录析构为其组件属性:

var person = new Person("Bill", "Wagner");


var (first, last) = person;

Console.WriteLine(first);

Console.WriteLine(last);

最后,记录支持 with 表达式。 with 表达式指示编译器创建记录的副本,但修改了指定的属性:

Person brother = person with { FirstName = "Paul" };


上述行创建新的 Person 记录,其中 LastName属性是 person 的副本,FirstName 为“Paul”。 可在 with 表达式中设置任意数量的属性。 你可编写除“克隆”方法以外的任何合成成员。 如果记录类型的方法与任何合成方法的签名匹配,则编译器不会合成该方法。 较早的 Dog 记录示例包含手动编码的 ToString() 方法作为示例。

相关推荐

pyproject.toml到底是什么东西?(py trim)

最近,在Twitter上有一个Python项目的维护者,他的项目因为构建失败而出现了一些bug(这个特别的项目不提供wheel,只提供sdist)。最终,发现这个bug是由于这个项目使用了一个pypr...

BDP服务平台SDK for Python3发布(bdp数据平台)

下载地址https://github.com/imysm/opends-sdk-python3.git说明最近在开发和bdp平台有关的项目,用到了bdp的python的sdk,但是官方是基于p...

Python-for-Android (p4a):(python-for-android p4a windows)

一、Python-for-Android(p4a)简介Python-for-Android(p4a),一个强大的开发工具,能够将你的Python应用程序打包成可在Android设备上运行...

Qt for Python—Qt Designer 概览

前言本系列第三篇文章(QtforPython学习笔记—应用程序初探)、第四篇文章(QtforPython学习笔记—应用程序再探)中均是使用纯代码方式来开发PySide6GUI应用程序...

Python:判断质数(jmu-python-判断质数)

#Python:判断质数defisPrime(n):foriinrange(2,n):ifn%i==0:return0re...

为什么那么多人讨厌Python(为什么python这么难)

Python那么棒,为什么那么多人讨厌它呢?我整理了一下,主要有这些原因:用缩进替代大括号许多人抱怨Python完全依赖于缩进来创建代码块,代码多一点就很难看到函数在哪里结束,那么你就需要把一个函数拆...

一文了解 Python 中带有 else 的循环语句 for-else/while-else

在本文中,我们将向您介绍如何在python中使用带有else的for/while循环语句。可能许多人对循环和else一起使用感到困惑,因为在if-else选择结构中else正常...

python的numpy向量化语句为什么会比for快?

我们先来看看,python之类语言的for循环,和其它语言相比,额外付出了什么。我们知道,python是解释执行的。举例来说,执行x=1234+5678,对编译型语言,是从内存读入两个shor...

开眼界!Python遍历文件可以这样做

来源:【公众号】Python技术Python对于文件夹或者文件的遍历一般有两种操作方法,一种是至二级利用其封装好的walk方法操作:import osfor root,d...

告别简单format()!Python Formatter类让你的代码更专业

Python中Formatter类是string模块中的一个重要类,它实现了Python字符串格式化的底层机制,允许开发者创建自定义的格式化行为。通过深入理解Formatter类的工作原理和使用方法,...

python学习——038如何将for循环改写成列表推导式

在Python里,列表推导式是一种能够简洁生成列表的表达式,可用于替换普通的for循环。下面是列表推导式的基本语法和常见应用场景。基本语法result=[]foriteminite...

详谈for循环和while循环的区别(for循环语句与while循环语句有什么区别)

初九,潜龙勿用在刚开始使用python循环语句时,经常会遇到for循环和while循环的混用,不清楚该如何选择;今天就对这2个循环语句做深入的分析,让大家更好地了解这2个循环语句以方便后续学习的加深。...

Python编程基础:循环结构for和while

Python中的循环结构包括两个,一是遍历循环(for循环),一是条件循环(while循环)。遍历循环遍历循环(for循环)会挨个访问序列或可迭代对象的元素,并执行里面的代码块。foriinra...

学习编程第154天 python编程 for循环输出菱形图

今天学习的是刘金玉老师零基础Python教程第38期,主要内容是python编程for循环输出菱形※。(一)利用for循环输出菱形形状的*号图形1.思路:将菱形分解为上下两个部分三角形图案,分别利用...

python 10个堪称完美的for循环实践

在Python中,for循环的高效使用能显著提升代码性能和可读性。以下是10个堪称完美的for循环实践,涵盖数据处理、算法优化和Pythonic编程风格:1.遍历列表同时获取索引(enumerate...