如何在 C# 9 中复制/克隆记录?

mba*_*amo 18 c# clone copy record c#-9.0

C#9的记录功能规范包括以下内容:

一个记录类型包含两个复制成员:

采用记录类型的单个参数的构造函数。它被称为“复制构造函数”。具有编译器保留名称的合成公共无参数实例“克隆”方法

但我似乎无法调用这两个复制成员中的任何一个:

public record R(int A);
// ...
var r2 = new R(r); // ERROR: inaccessible due to protection level
var r3 = r.Clone(); // ERROR: R does not contain a definition for Clone
Run Code Online (Sandbox Code Playgroud)

由此,我了解到构造函数是受保护的,因此无法在记录的继承层次结构之外访问。所以我们只剩下这样的代码:

var r4 = r with { };
Run Code Online (Sandbox Code Playgroud)

但是克隆呢?根据上述规范,克隆方法是公开的。但它的名字是什么?或者它是一个有效的随机字符串,因此不应在记录的继承层次结构之外调用它?如果是这样,深复制记录的正确方法是什么?从规范看来,人们可以创建自己的克隆方法。是这样吗,它应该如何工作的一个例子是什么?

Yai*_*adt 15

但是克隆呢?

var r4 = r with { };
Run Code Online (Sandbox Code Playgroud)

在 r 上执行浅克隆。

根据上述规范,克隆方法是公开的。但它的名字是什么?

C# 编译器有一个相当常见的技巧,它给出生成的成员名称,这些名称在 C# 中是非法的,但在 IL 中是合法的,因此除了编译器之外,它们不能被调用,即使它们是公共的。在这种情况下,Clone方法的名称是<Clone>$

如果是这样,深复制记录的正确方法是什么?

深度复制你不走运。然而,由于理想情况下记录应该是不可变的,因此浅拷贝、深拷贝和原始实例在实践中应该没有区别。

从规范看来,人们可以创建自己的克隆方法。是这样吗,它应该如何工作的一个例子是什么?

不幸的是,这并没有在 C# 9 中脱颖而出,但它很有可能会出现在 C# 10 中。

  • 是否有关于 C# 10 中自定义“Clone”的讨论?感觉引入它会使其遇到“ICloneable”始终遇到的相同问题,不知道“&lt;Clone&gt;$”是否会进行浅层克隆或自定义深度克隆。 (4认同)
  • @John - “with”表达式现在适用于“struct”类型和“record”。但**不是** `class` 类型。https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#nonpressive-mutation (2认同)

小智 11

要执行深度克隆,您可以将自己的复制构造函数添加到记录中:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public record EmployeeRecord(int UniqueId, Person Employee)
{

    // Custom copy constructor (Should be protected or private)
    protected EmployeeRecord(EmployeeRecord other)
    {
        UniqueId = other.UniqueId;

        // Do deep copy stuff
        Employee = new Person 
        { 
            FirstName = Employee.FirstName, 
            LastName = Employee.LastName 
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器不会生成自己的。然后使用“with”关键字:

var emp1 = new EmployeeRecord(100, 
    new Person { FirstName = "John", LastName = "Doe" });

var emp2 = emp1 with { };
Run Code Online (Sandbox Code Playgroud)