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

Posted

技术标签:

【中文标题】如何在 C# 9 中复制/克隆记录?【英文标题】:How to copy/clone records in C# 9? 【发布时间】:2021-01-07 16:17:00 【问题描述】:

C# 9 records feature specification 包括以下内容:

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

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

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

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

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

var r4 = r with  ;

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

【问题讨论】:

“但是克隆呢?” 这就是with 表达式的作用。您不应该知道“克隆”方法的名称。这就是“编译器保留”的意思。它支持with 表达式。 表上的实现细节:名字是<Clone>$。按照设计,您不能自己调用​​它。 它没有。这种克隆机制是浅拷贝。您链接的文档在任何地方都不包含“深度”一词。如果你想要一个深拷贝,你需要自己实现。 @madreflection 谢谢。我认为让我感到困惑的是文档中“复制”和“克隆”的使用,但是您没有使用“深度”这个词是正确的,因此必须以其他方式实现。我也对文档的声明“如果基本记录中存在虚拟“克隆”方法,......”感到困惑,据我所知,这始终是综合创建的 Clone() 方法,而不是用户定义的一;尝试自己创建这样的方法会产生错误。 应该注意 imo,“浅拷贝”是一个定义明确的概念,而“深拷贝”不是。 【参考方案1】:

但是克隆呢?

var r4 = r with  ;

在 r 上执行浅层克隆。

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

C# 编译器有一个相当常见的技巧,它为生成的成员提供名称,这些名称在 C# 中是非法的,但在 IL 中是合法的,因此即使它们是公共的,也无法从编译器中调用它们。在这种情况下,Clone 方法的名称是 <Clone>$

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

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

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

很遗憾,这并没有进入 C# 9,但很有可能会出现在 C# 10 中。

【讨论】:

是否有关于 C# 10 中的自定义 Clone 的讨论?感觉就像引入它会使其遭受ICloneable 一直存在的相同问题,不知道<Clone>$ 是否会进行浅克隆或自定义深度克隆。 对于 C# 10 根本没有讨论过。也许 C# 11... 所以他们引入了表达式,并且只对记录起作用,不能用于其他任何东西? 现在,是的@John

以上是关于如何在 C# 9 中复制/克隆记录?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 CakePhp 克隆/复制 sql 记录?

如何克隆 InputStream 以允许从两个流(原始和克隆)中读取? [复制]

如何打造网站克隆仿站工具(C#版)

如何在 C# 中克隆 DateTime 对象?

如何在 kotlin 中克隆或复制列表

如何在 C# 中进行完全外连接? [复制]