为什么在 C# 中记录类默认是不可变的,但记录结构却不是?

ser*_*0ne 16 c# record immutability

我被教导结构应该几乎总是不可变的,因此记录类与记录结构的这种不寻常行为让我措手不及。

使用记录类...

record class Person(string FirstName, string LastName);
Person p = new("John", "Smith");
p.FirstName = "Jack" // Not allowed!
Run Code Online (Sandbox Code Playgroud)

使用记录结构...

record struct Person(string FirstName, string LastName);
Person p = new("John", "Smith");
p.FirstName = "Jack" // Fine!
Run Code Online (Sandbox Code Playgroud)

使用只读记录结构...

readonly record struct Person(string FirstName, string LastName);
Person p = new("John", "Smith");
p.FirstName = "Jack" // Now allowed!
Run Code Online (Sandbox Code Playgroud)

为什么readonly记录结构默认是可变的,为什么相同的行为不适用于记录类?

编辑:我想我在这里问的是,为什么语法......很奇怪?

例如,看起来更合乎逻辑:

  • record class-具有值语义的可变引用类型。
  • readonly record class-具有值语义的不可变引用类型。
  • record struct-具有值语义的可变值类型。
  • readonly record struct-具有值语义的不可变值类型。

Rya*_*son 14

直接取自 Microsoft MVP 工程师 \xc4\xb0lkay \xc4\xb0lknur:

\n
\n

大多数生成的代码看起来与记录类相似。\n但是,记录结构和记录类之间有一个区别。\n 默认情况下,记录结构中生成的属性是可变的。这个决定背后的原因是为了与元组保持一致。元组就像具有相似功能的匿名记录结构。\n 另一方面,结构体可变性并不像类可变性那样受到同样程度的关注。这就是 C# 团队决定让记录结构属性默认可变的原因。但是,如果您需要不可变的记录结构,则可以使用 readonly 关键字。

\n
\n

csharp 中的记录结构

\n


小智 7

如果您使用位置语法来定义 a record class,它的属性是不可变的

record class Point(int X, int Y);
Run Code Online (Sandbox Code Playgroud)

它默认具有属性附件{get; init;}

如果您以传统方式声明这一点(没有位置参数),您可以指定您的属性访问器:

record class Point
{
    int X {get; set;}
    int Y {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

您可以混合搭配这两种样式,但请记住,如果您提供任何位置参数,它们将成为自动实现的构造函数上的参数,并且不会设置任何其他属性。

我意识到这实际上并不能回答为什么这种行为存在的问题,我只是希望阅读本文的人不会得出record class不可改变的结论。