3.12C#类型之记录结构(record struct)和记录类(record class)

记录声明

声明记录类型的语法与声明结构或类的语法类似。只需将record struct代替struct,或使用record代替class

记录的参数是记录的public属性。

记录结构(record struct)是值类型,记录类(record class)是引用类型。

record struct 结构名(参数);
record [class] 类名(参数);

继承

记录结构不支持继承,因为结构不支持继承。

记录类支持继承,与表达继承关系的类语法相同。记录与类之间不可相互继承。

创建对象

记录结构或记录类的对象创建方式与结构或类相同。

以下示例定义了一个公共记录,该记录使用位置参数来声明和实例化记录。然后打印类型名称和属性值:

public record Person(string FirstName, string LastName);

public static void Main()
{
    Person person = new("Nancy", "Davolio");
    Console.WriteLine(person);
    // output: Person { FirstName = Nancy, LastName = Davolio }
}

不同的是:记录类型是一种 不可变类型(immutable type) ,记录类型的对象一旦被创建以后,不可更改其任何字段或属性的值。

值相等(value equality)和引用相等(reference equality)

记录类型通常被用来对记录类型的对象进行 值相等(value equality)引用相等(reference equality) 的比较。

值相等(value equality) 使用 Equals 方法(同等的运算符==)比较对象的记录类型且所有字段和属性的实参值是否相同,如果相同,则这两个对象 值相等

引用相等(reference equality) 使用 ReferenceEquals 方法比较它们是否是相同的对象,如果相同,则这两个对象 引用相等

以下示例演示了记录类型的对象的值相等和引用相等:

public record Person(string FirstName, string LastName, string[] PhoneNumbers);

public static void Main()
{
    var phoneNumbers = new string[2];
    Person person1 = new("Nancy", "Davolio", phoneNumbers);
    Person person2 = new("Nancy", "Davolio", phoneNumbers);
    Console.WriteLine(person1 == person2); 
    // person1和person2类型都是Person记录类型且所有字段和属性的实参值相等,所以output: True

    person1.PhoneNumbers[0] = "555-1234";
    Console.WriteLine(person1 == person2); 
    // 数组是引用类型,所以output: True

    Console.WriteLine(ReferenceEquals(person1, person2)); 
    // 即使值相等,但person1和person2都属于独立的两个新建的对象,所以不引用同一个对象output: False
}

记录类型内的方法与运算符的相等性使用值相等。

并非所有数据模型都适用于 值相等。例如,Entity Framework Core依赖于 引用相等 来确保它只使用实体类型的一个实例来表示概念上的一个实体。因此,记录类型不适合用作 Entity Framework Core 中的实体类型。

不可变类型(immutable type)

with表达式会创建新的对象,此新的对象是已存在对象的副本与特定属性的值被更改后的新对象。换言之,with表达式创建的对象与原对象不属于同一个对象。

以下示例演示了使用with表达式来复制不可变类型的对象并更改其中一个属性:

public record Person(string FirstName, string LastName)
{
    public string[] PhoneNumbers { get; init; }
}

public static void Main()
{
    Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
    Console.WriteLine(person1);
    // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }

    Person person2 = person1 with { FirstName = "John" };
    Console.WriteLine(person2);
    // output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
    Console.WriteLine(person1 == person2);
    // person1和person2类型都是Person记录类型,但FirstName属性的值不同,所以output: False

    person2 = person1 with { PhoneNumbers = new string[1] };
    Console.WriteLine(person2);
    // output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
    Console.WriteLine(person1 == person2); 
    // 数组是引用类型,所以output: False

    person2 = person1 with { };
    Console.WriteLine(person1 == person2); 
    // person2是person1的副本,所以output: True
}

当您需要一种类型是线程安全的或者您依赖于在哈希表中保持相同的哈希码时,不可变类型很有用。

不可变类型并不适用于所有数据场景。例如,Entity Framework Core不支持使用不可变实体类型进行更新。

原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/csharp/csharplang/11948.html

发表评论

登录后才能评论