设计一个可变类,它被消耗后变得不可变 [英] Design a mutable class that after it's consumed becomes immutable
问题描述
public class ObjectAConfig {
private int _valueB;
private string _valueA;
内部bool消耗{get;组; }
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;
}
}
}
当 ObjectA
消耗 ObjectAConfig
:
public ObjectA {
public ObjectA(ObjectAConfig config){
_config = config;
_config.Consumed = true;
}
}
我不满意,这只是工作,我'我想知道是否有更好的模式(排除在外),从开始就设计从 ObjectAConfig
不可变。
例如:
-
可以有意义地定义一个像
一个< T> code>允许将包装值初始化一次?
-
可以有意义地定义返回类型本身更改私有字段的类型吗?
你实际执行的时间有时会以冰棒不变性 - 即你可以冻结它。您现在的方法将会工作 - 确实我在许多地方自己使用这种模式。
您可以通过以下方式减少一些重复: p>
private void SetField< T>(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()
{
返回新的ImmutableConfig(ValueA,ValueB);
}
... snip:实现ObjectAConfig
}
这里有一个真正不可变的实现 IConfig
和你原来的实现。如果您想要冻结版本,请致电 Build()
。
Suppose that the scenario doesn't allow to implement an immutable type. Following that assumption, I'd like opinions / examples on how to properly design a type that after it's consumed, becomes immutable.
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;
}
}
}
When ObjectA
consumes ObjectAConfig
:
public ObjectA {
public ObjectA(ObjectAConfig config) {
_config = config;
_config.Consumed = true;
}
}
I'm not satisfied that this simply works, I'd like to know if there's a better pattern (excluded, as said, making ObjectAConfig
immutable by design from begin).
For example:
can make sense define a monad like
Once<T>
that allow the wrapped value to be initialized only once?can make sense define a type that returns the type itself changing a private field?
What you are implementing sometimes goes under the name "popsicle immutability" - i.e. you can freeze it. Your current approach will work - indeed I use that pattern myself in numerous places.
You can probably reduce some duplication via something like:
private void SetField<T>(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); }
}
There is another related approach, though: a builder. For example, taking your existing class:
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
}
Here there is a truly immutable implementation of IConfig
, and your original implementation. If you want the frozen version, call Build()
.
这篇关于设计一个可变类,它被消耗后变得不可变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!