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
。我需要的其实只是:
- 可以传递给另一个模块的不可变类型(无需担心接收方修改内容影响发送方)。
- 只需稍作修改即可轻松克隆。
您可以使用 record
s, introduced in C# 9, or if being a value type is also a requirement, use record struct
s,在 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.");
我有几个包含信息的不可变 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
。我需要的其实只是:
- 可以传递给另一个模块的不可变类型(无需担心接收方修改内容影响发送方)。
- 只需稍作修改即可轻松克隆。
您可以使用 record
s, introduced in C# 9, or if being a value type is also a requirement, use record struct
s,在 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.");