【.NET Core】记录(Record)详解

news/2024/5/19 23:24:25 标签: .netcore, linq, c#, asp.net, 开发语言

【.NET Core】记录(Record)详解

文章目录

  • 【.NET Core】记录(Record)详解
    • 一、什么是记录
    • 二、定义一个记录
      • 2.1 使用record(或record class)定义引用类型
      • 2.2 使用record struct定义值类型
      • 2.3 创建可变记录类型
    • 三、记录类型提供哪些功能
    • 四、引用类型记录和值类型记录区别
    • 五、Recode常用属性
      • 5.1 属性定义的位置语法
      • 5.2 不可变性
      • 5.3 值相等性
      • 5.4 非破坏性变化
      • 5.5 继承
    • 六、总结

一、什么是记录

record修饰符定义一个引用类型,用来提供用于封装数据的内置功能。C# 10允许recode class语法作为同义词来阐明引用类型,并允许recode struct使用相同功能定义值类型。本文将重点讲解recode在实际中的使用。

在记录(record)上声明主构造函数时,编译器会为主构造函数参数生成公共属性。记录的主构造函数参数称为位置参数。编译器创建镜像主构造函数或位置参数的位置属性。编译器不会在没有record修饰符的类型上合成主构造函数参数的属性。

二、定义一个记录

2.1 使用record(或record class)定义引用类型

c#">public record Person(string name,string address,int age);
c#">public record Person
{
    public required string name{get;init;}
    public required string address{get;init;}
    public required int address{get;init;}
}

2.2 使用record struct定义值类型

c#">public readonly record struct Point(double X,double Y,double Z);
c#">public record struct Point
{
    public double X{get;init;}
    public double Y{get;init;}
    public double Z{get;init;}
}

记录(record)定义了一些不可变的类型,其实记录也可以创建为可变的类型。但是record主要用于支持不可变的数据模型中。记录创建为可变属性和字段的记录如下:

2.3 创建可变记录类型

创建可变引用类型记录

c#">public record Person
{
    public required string FirstName { get; set; }
    public required string LastName { get; set; }
};

创建结构型记录

public record struct Point
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
}

三、记录类型提供哪些功能

  • 用于创建具有不可变属性的引用类型的简明语法。
  • 内置行为对于数据为中心的引用类型可用于:
    • 值相等性
    • 非破坏性变化的简明语法
    • 用于显示的内置格式设置
  • 支持继承层次结构

四、引用类型记录和值类型记录区别

  • recordrecord class声明引用类型。class关键字是可选项,但可以提供代码辨识度。record struct声明值类型。
  • 记录属性和readonly record struct中不可变。

record一词用于描述应用于所有记录类型的行为。record structrecord class用于描述仅适用于struct或class类型的行为。

五、Recode常用属性

5.1 属性定义的位置语法

在创建Recode实例时,可以使用位置参数来声明记录的属性,并初始化属性值:

c#">public record Person(string UserName,int UserAge);
public static void Main()
{
    Person person=new("诸葛亮",59);
    Console.WriteLine(person);
}

属性定义使用位置语法时,编译器将执行一下操作:

  • 为记录声明中提供的每个位置参数提供一个公共的自动实现的属性。
    • 对于recordreadonly record struct类型,为record属性。
    • 对于record struct类型,为读写属性。
  • 主构造函数,它的参数与记录声明上的位置参数匹配。
  • 对于record struct类型,则是将每个字段设置为其默认值的无参数构造函数。
  • 一个Deconstruct方法,对记录声明中提供的每个位置参数都一个out参数。此方法解构了使用位置语法定义的属性;并忽略了使用标准的属性语法定义的属性。

如果生成的自动实现的属性定义并不是你所需要的,你可以自行定义同名的属性。例如,你可能想要更改可访问性或可变性,或者为getset访问器提供实现。如果在源中声明属性,则必须从记录的位置参数初始化该属性。如果属性是自动实现的属性,则必须初始化该属性。如果在源中添加支持字段,则必须初始化支持字段。生成的析构函数将使用属性定义。

5.2 不可变性

positional recordpositional readonly record struct声明init-only属性。positional record struct声明read-write属性性,可以替代这些默认值中的任何一个。

如果你需要一个以数据为中心的类型是线程安全的,或者需要使哈希代码保持不变,那么不可变性很有用。但不可变性并不是适用于所有的数据场景。例如,Entity Framework Core就不支持通过不可变实体类型进行更新。

init-only属性无论是通过位置参数(record classreadonly record struct)创建的,还是通过指定init访问器创建的,都具有浅的不可变性。初始化后,将不能更改值型的值或引用类型的引用地址。不过,引用类型引用的数据是可以更改的,下面示例展示了引用型不可变属性的内容时可变的:

c#">public record Person(string UserName,int UserAge,String[] UserPhones);
public static void Main()
{
    Person person=new("诸葛亮",55,new string[1]{"010-6689012"});
    Console.WriteLine(person.UserPhones[0]);// output:010-6689012
    person.PhoneNumbers[0] = "010-6689018";
    Console.WriteLine(person.UserPhones[0]);// output:010-6689018  
}

记录类型持有功能是由编译器合成的方法实现的,这些方法都不会通过修改对象状态来影响不可变性。除非另行指定,否则将为record,record structreadonly record struct声明生成综合方法。

5.3 值相等性

如果不替代或替换相等性方法,则声明的类型将控制如何定义相等性。

  • 对于class类型,如果两个对象引用内存中的同一个对象,则这两个对象相等。
  • 对于struct类型,如果两个对象是相同的类型并存储相同的值,则这两个对象相等。
  • 对于具有record修饰符(record classrecord structreadonly record struct)的类型,如果两个对象是相同的类型并存储相同的值,则这两个对象相等。

record struct的相等性定义与struct的相等性定义相同。不同之处在于,对于struct,实现处于ValueType.Equals(Object)中并且依赖反射,对于记录,实现由编译器合成,并且使用声明的数据成员。

5.4 非破坏性变化

如果需要复制包含一些修饰的实例,可以使用with表达式来实现非破坏性变化。with表达式创建一个新的记录实例,该实例是现有记录的实例的一个副本,修改了指定属性和字段。使用对象初始化设定项语法指定要更改的值,实例如下:

c#">public record Person(string userName,int userAge)
{
   public string[] userPhone {get;init;}
}
public static void Main()
{
  Person person1=new("诸葛亮",35);
  Console.WriteLine(person1);
  //output:Person{userName=诸葛亮,userAge=35,userPhone=System.String[]}
  Person person2= person1 with {userName="赵云"};
  Console.WriteLine(person2);
  //output:Person{userName=赵云,userAge=35,userPhone=System.String[]}
  Console.WriteLine(person1 == person2);
  //output:False
    
}

with表达式可以设置位置属性或使用标准属性语法创建的属性。显示声明属性必须有一个initset访问器才能在with表达式中进行更改。

with表达式的结果是一个浅的副本,这意味着对于引用属性,只复制对实例的引用。原始记录和副本最终都具有对同一个实例的引用。

为了对record class类型实现此功能,编译器合成了一个克隆方法和一个复制构造函数,虚拟克隆方法返回由复制构造函数初始化的新记录,当使用with表达式时,编译器将创建调用克隆方法的代码,然后设置with表达式中指定的属性。

5.5 继承

record继承仅适用于record class类型。一条记录可以从另一条记录继承。但是记录不能继承类,类也不能继承记录类。

派生记录为基本记录主构造函数中的所有参数声明位置参数。基本记录声明并初始化这些属性。派生记录不会隐藏它们,而只会创建和初始化在基本记录中声明的参数的属性。

public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
    : Person(FirstName, LastName);
public static void Main()
{
    Person teacher = new Teacher("Nancy", "Davolio", 3);
    Console.WriteLine(teacher);
    // output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}

六、总结

记录是一个语法糖,本质上还是class或者struct,它只编译时生效,在公共语言运行时中并不存在记录这个内容。


http://www.niftyadmin.cn/n/5304526.html

相关文章

微服务注册中心之Eureka

微服务注册中心之Eureka eureka 搭建集群 版本说明 Spring Boot 2.1.7.RELEASE spring-cloud-starter-netflix-eureka-server Finchley.SR2 spring-boot-starter-security 2.1.7.RELEASE pom.xml 文件 <?xml version"1.0" encoding"UTF-8"?> &l…

【大数据】分布式协调系统 Zookeeper

分布式协调系统 Zookeeper 1.Zookeeper 的特点2.Zookeeper 的数据结构3.Zookeeper 的应用场景3.1 统一命名服务3.2 统一配置管理3.3 统一集群管理3.4 服务器动态上下线3.5 软负载均衡 Zookeeper 是 Apache 开源的一个顶级项目&#xff0c;目的是为分布式应用提供协调服务&#…

Linux第2步_创建虚拟机

VMware软件安装好后&#xff0c;就可以创建虚拟机了。 一、虚拟机对CPU的要求较高 i7 处理器&#xff1a;CPU&#xff1a;Intel(R) Core(TM) i7-8700 CPU 3.20GHz 3.19 GHz 内核数&#xff1a;6 线程数&#xff1a; 12 最大睿频频率&#xff1a; 4.60 GHz 英特尔 睿…

阶段十-分布式-Redis01

第一章 Redis入门 1.1 节 什么是NoSql型数据库 NoSQL ,泛指非关系型的数据库, NoSQL Not Only SQL,它可以作为关系型数据库的良好补充。 NoSQL 不依赖业务逻辑方式存储&#xff0c;而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。NoSQL与SQL数据库区别对比如…

自由DIY预约小程序源码系统:适用于任何行业+自由DIY你的界面布局+全新升级的UI+多用户系统 带安装部署教程

随着移动互联网的普及&#xff0c;预约服务逐渐成为人们日常生活的一部分。从家政服务、医疗挂号到汽车保养&#xff0c;预约已经渗透到各个行业。然而&#xff0c;市面上的预约小程序大多功能单一&#xff0c;界面老旧&#xff0c;无法满足商家和用户的个性化需求。今天来给大…

计算机网络——多址复用技术

1. 频分多址&#xff08;FDMA&#xff09; 1.1 基本原理 频率分配&#xff1a;在FDMA系统中&#xff0c;整个可用的频带被分割成多个较小的频带或通道。每个通道分配给一个用户。 时间利用&#xff1a;用户在分配给他们的频道上持续进行通信&#xff0c;不受时间限制。 1.2 优…

Elasticsearch:Serarch tutorial - 使用 Python 进行搜索 (一)

本实践教程将教你如何使用 Elasticsearch 构建完整的搜索解决方案。 在本教程中你将学习&#xff1a; 如何对数据集执行全文关键字搜索&#xff08;可选使用过滤器&#xff09;如何使用机器学习模型生成、存储和搜索密集向量嵌入如何使用 ELSER 模型生成和搜索稀疏向量如何使用…

【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建

【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 概述-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行环境搭建-CSDN博客 【大数据进阶第二阶段之Hadoop学习笔记】Hadoop 运行模式-CSDN博客 1、模板虚拟机环境准备 1.1、 hadoop100 虚拟机配置要求如下 &…