设计一个可变类,在它被消耗后变为不可变类

假设场景不允许实现不可变类型。 按照这个假设,我想了解如何正确设计一个在消费后变成不可变的类型的意见/例子。

public class ObjectAConfig { private int _valueB; private string _valueA; internal bool Consumed { get; set; } public int ValueB { get { return _valueB; } set { if (Consumed) throw new InvalidOperationException(); _valueB = value; } } public string ValueA { get { return _valueA; } set { if (Consumed) throw new InvalidOperationException(); _valueA = value; } } } 

ObjectAConfig

 public ObjectA { public ObjectA(ObjectAConfig config) { _config = config; _config.Consumed = true; } } 

我不满意这简单的工作,我想知道是否有更好的模式(排除,如所说,使ObjectAConfig从设计开始不可变)。

例如:

  • 可以理解定义像Once这样的monad只允许包装的值初始化一次吗?

  • 有意义定义一个返回类型本身改变私有字段的类型?

您实施的有时会以“ 冰棒不变性 ”为名称 – 即您可以将其冻结。 你当前的方法会起作用 – 事实上我在很多地方都使用这种模式。

您可以通过以下方式减少一些重复:

 private void SetField(ref T field, T value) { if (Consumed) throw new InvalidOperationException(); field = value; } public int ValueB { get { return _valueB; } set { SetField(ref _valueB, value); } } public string ValueA { get { return _valueA; } set { SetField(ref _valueA, value); } } 

不过还有另一种相关的方法:建设者。 例如,拿走现有的课程:

 public interface IConfig { string ValueA { get; } int ValueB { get; } } public class ObjectAConfig : IConfig { private class ImmutableConfig : IConfig { private readonly string valueA; private readonly int valueB; public ImmutableConfig(string valueA, int valueB) { this.valueA = valueA; this.valueB = valueB; } } public IConfig Build() { return new ImmutableConfig(ValueA, ValueB); } ... snip: implementation of ObjectAConfig } 

这里有一个真正不可变的IConfig实现,以及您原来的实现。 如果您想要冻结版本,请调用Build()