C#9.0记录类型

.net 5支持C#9.0

记录类型

    引用类型

    提供合成方法来提供值语义,从而实现相等性。默认情况下,记录是不可变的。

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

不可变的引用类型。记录为不可变的引用类型提供类型声明,该引用类型使用值语义实现相等性。

如果用于实现相等性的合成方法的属性和哈希代码的属性都相等,则认为两条记录相等。

请考虑一下定义:

public record Person

{

    public string LastName{get;}

    public string FirstName{get;}

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

}

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

    基于值的相等性比较方法

    替代GetHashCode()

    复制和克隆成员

    PrintMembers和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。

    记录具有为你生成的一致的字符串表示形式。

    记录支持副本构造。正确的副本构造必须包括继承层次结构和开发人员添加属性。

    可通过修改复制记录。这些复制和修改操作支持非破坏性转变。

除了熟悉的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 Studemt(string FirstName,string LastName,int Level):Person(FirstName,LastName);

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

    publicrecordPet(stringName)

    {

        publicvoidShredTheFurniture() =>Console.WriteLine("Shredding furniture");

    }

    publicrecordDog(stringName) :Pet(Name)

    {

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

        publicoverridestringToString()    

        {

            StringBuilder s = new();base.PrintMembers(s);

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

    }

}

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

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

    var (first,last)=person;

    Console.WriteLine(first);

    Constle.WriteLine(last);

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

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

上一行创建新的Person记录,其中LastName属性是person的副本,FirstName为"Paul"。可在with表达式中设置任意数量的属性。还可以使用with表达式来创建精确的副本。为要修改的属性指定空集:

    Person clone=person with {};

你可编写除“克隆”方法以外的任何合成成员。 如果记录类型的方法与任何合成方法的签名匹配,则编译器不会合成该方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容