在C#中的数据类型主要分为引用类型和值类型。
C#9.0中引入了记录(record)类型,它是一种特殊的引用类型,它提供合成方法来提供值类型相等性的语义。也就是说,使用record类型可以创建出不可变的引用类型,但是有类似于值类型的行为。譬如可以使用基于值相等性的比较方法,相同值的实例有相同的HashCode。
声明一个结构用struct关键字,声明一个类用class关键字,C#9.0中引入了一个新的关键字record,使用record关键字来声明一个不可变类型。
不可变类型可以理解为:一旦对象实例化或初始化,不变类型就永远不会改变。不可变的类型只有一种状态,就是在创建对象时指定的状态。
定义一个record类型:
publicrecordDemo{publicstringName1{get;set;}publicstringName2{get;init;}}
注:如果不了解init关键字,请参考C#9.0中的Init-Only属性。
与class一样,record也有一些类的特性,譬如:
record支持继承
可以使用abstract、sealed等修饰符
下面做个非常简单的研究。
定义一个Person的class:
publicclassPerson{publicstringFirstName{get;init;}publicstringLastName{get;init;}}
实例化两个Person对象,并进行对比:
Personperson1=newPerson{FirstName="San",LastName="Zhang"};Personperson2=newPerson{FirstName="San",LastName="Zhang"};Console.WriteLine(person1.GetHashCode());Console.WriteLine(person2.GetHashCode());Console.WriteLine(person1==person2);Console.WriteLine(person1.Equals(person2));
虽然person1和person2都是Person的实例,但是由于是引用类型,在两次实例化之后,两个实例在内存空间中就分配了不一样的地址,所以在不重写Equals方法或运算符重载的情况下,直接对比两个实例,结果肯定是不相等的。
简单看一下运行后的输出结果:
dotnetrunFalseFalse
将Person改成record:
publicrecordPerson{publicstringFirstName{get;init;}publicstringLastName{get;init;}}
实例化两个Person对象:
Personperson1=newPerson{FirstName="San",LastName="Zhang"};Personperson2=newPerson{FirstName="San",LastName="Zhang"};Console.WriteLine(person1.GetHashCode());Console.WriteLine(person2.GetHashCode());Console.WriteLine(person1==person2);Console.WriteLine(person1.Equals(person2));
简单看一下运行后的输出结果:
dotnetrunTrueTrue
可以看出,两个record类型的实例在属性的值相等的情况下,HashCode和对比运算的计算结果都是相同的,具有类似于值类型相同的行为。
那什么情况下使用record类型或使用record有什么好处呢?
record类型在使用消息传递时和在大型的分布式体系结构中非常有用。当对象是不可变类型时候,我们不必担心应用程序的其他部分会对其进行修改。
record类型可以减少某些情况下使用lock的需要,并简化了系统中所有高度并发的部分。
record类型是线程安全的,不需要修改也不需要进行状态同步,同时没有占用修改对象的线程,所以可以自由的共享。
record类型的最大好处是减少了所需的内存分配,由于不可变,所以除了原始记录分配之外,不需要其他内存分配。
注意:
如果定义的record和class类型的属性都是init的时候,虽然都可以实现不可变类型,但是通过合成方法,record类型会有值类型相等的语义。
全栈哥点开,斐波那契!