C# 通过修改复制不可变结构?

C# copying an immutable struct with modification?

我有几个包含信息的不可变 struct,例如

public struct Human {
  public readonly string Name;
  public readonly int Age;
  // ... 50 other variables that describe a human
}

现在我想克隆一个 Human 结构,但只更改 1 个值。我当然可以这样做:

var newSelf = new Human(
  oldSelf.Name,
  oldSelf.Age + 1,
  // ... 50 more lines here
)

但是如您所见,为我制作的每个结构输入 50 次 oldSelf.XYZ 真的很乏味。

所以我正在寻找这样的东西:

// copy all variable from oldSelf to a new struct, but change the name and increase Age by 1
var newSelf = oldSelf.CloneWithModification(("Name", "Valeria"), ("Age", oldSelf.Age + 1));

我不太喜欢struct。我需要的其实只是:

您可以使用 records, introduced in C# 9, or if being a value type is also a requirement, use record structs,在 C# 10 中引入。

public record Human {
  public string Name { get; init; }
  public int Age { get; init; }
  // ... 50 other variables that describe a human
}

然后您可以使用 with expression 创建 Human 的副本,仅更改一些属性。请注意,这使用了 init 访问器。

Human human = ...
var newHuman = human with { Age = human.Age + 1 }; // this creates a copy

不使用 record 您可以按照 following pattern

public Human WithName(string value)
   => value == Name
      ? this
      : new Human(value, Age, ...);

public Human WithAge(int value)
   => value == Age
      ? this
      : new Human(Name, value, ...);

...

如果您可以访问 C# 9.0 或更高版本,我支持使用其他答案中提到的 with 运算符。

C#9.0以下,可以考虑使用MemberwiseClone()方式。它是受保护的,所以你只能从另一个方法调用它,不能在 class 之外。例如:

public struct Human {
    public string Name { get; private set; }
    public int Age { get; private set; }
    
    public Human(string name, int age) {
        this.Name = name;
        this.Age = age;
    }

    public Human WithAge(int age) {
        var result = (Human)this.MemberwiseClone();
        result.Age = age;
        return result;
    }

然后

var older = new Human("AVAVT", 70);
var younger = older.WithAge(18);

// Prints: "Younger is 18 years old."
System.Console.WriteLine($"Younger is {younger.Age} years old.");