在创建不可变类的新实例时保存值
本文关键字:实例 保存 不可变 创建 新实例 | 更新日期: 2023-09-27 18:14:39
我有一个不可变类F1:
public class F1
{
public readonly int field1;
public readonly int field2;
public readonly int field3;
public readonly int field4;
public readonly int field5;
......
public F1 SetField1(int f)
{
return new F1(f, field2, field3, field4, field5);
}
......
}
如果我需要改变一个字段,例如field1,我需要从方法中返回一个新的类实例。所有五个字段都传递给构造函数,即使其中四个没有更改。
没关系,如果我使用5个字段。但是如果我使用40个字段,我不能传递40个参数给构造函数。我需要做什么?我如何保存其他字段的值,并创建新的实例没有传递参数构造函数?
有一个我确实需要的不可变类。这是我工作的重要条件。
使用Object.MemberwiseClone()
方法,每个类都继承Object
。
public class F1
{
private int _field1;
public int Field1 { get return _field1; }
private int _field2;
public int Field2 { get return _field2; }
private int _field3;
public int Field3 { get return _field3; }
...
public F1 SetField1(int f)
{
var f1 = (F1)MemberwiseClone();
f1._field1 = f;
return f1;
}
...
}
通过只读属性(只有getter而没有setter的属性)公开字段来达到不可变性。
注意MemberwiseClone
只对原始对象做一个浅拷贝。如果这个对象只包含值类型的字段,或者所有引用类型字段都是不可变的(例如string
),这是可以的。否则,您可能也必须克隆这些字段。
一个有40个字段的类看起来很复杂,试着把它重构成几个更小的类。
为了避免编写太多的样板代码,您可以使用可选的可空参数(Carsten在他的评论中建议使用类似的方法)
class ImmutableClass
{
private readonly int _field1;
private readonly int _field2;
public ImmutableClass(int field1, int field2)
{
_field1 = field1;
_field2 = field2;
}
private ImmutableClass(ImmutableClass src, int? field1 = null, int? field2 = null)
{
_field1 = field1 ?? src._field1;
_field2 = field2 ?? src._field2;
}
//choose a more domain-related name
public ImmutableClass ModifyField1(int value)
{
return new ImmutableClass(this, field1: value);
}
//choose a more domain-related name
public ImmutableClass ModifyField2(int value)
{
return new ImmutableClass(this, field2: value);
}
//just an example - I wouldn't do it in my code
public ImmutableClass ModifyFields(int? field1 = null, int? field2 = null)
{
return new ImmutableClass(this, field1, field2);
}
}
您还可以使用带有私有setter的可变字段。这将允许您在返回新实例之前使用automapper等工具创建副本并设置修改后的字段。但是,这样的类可以使用反射来改变。