我正在构建一个包含许多互连对象的大型复杂数据结构。作为其中的一部分,我有一种情况,我需要在知道所有属性的值之前创建一个对象。这样我就可以在更大的数据结构内部传递对该对象的引用,然后稍后更改它以允许该对象的所有使用者获得"更新"值。
跟踪每个对象的使用者以便我可以更新他们的引用意味着我是A)重新实现引用计数垃圾收集器而B)将需要外部使用者来修改类。出于显而易见的原因,我不想实现垃圾收集器(或类似的东西)。并允许外部使用者修改属性意味着该对象是可变的。不可变性很重要,因为我知道这个数据结构中的许多对象将在构建数据结构之后在字典中结束,但我可以安全地修改属性。由于这是一个将提供给其他用户的库,我必须阻止会破坏字典不变量等内容的交互。
我正在实施这个"延迟初始化"像这样的属性的概念:
class MyClass
{
private AnotherClass mReference = null;
public bool Reference
{
get
{
return this.mReference
}
internal set
{
if ( this.mReference != null )
{
throw new Exception( "This value has already been initialized!" );
}
else
{
this.mReference = value;
}
}
}
}
我允许internal
范围内的任何内容为此属性分配一次非空值。一旦物业被设定,就不会再回头了。
虽然C#有一个已经执行此操作的关键字readonly
,但readonly
约束该成员只能通过静态初始值设定项或同一类中的构造函数来分配。但是在调用构造函数时,我不知道这个属性的值是什么!
我的问题是我现在在多个类中使用这个确切的模式,我想避免这个代码重复。
有没有人对如何减少代码重复有任何建议?可能是像readonly
这样的C#关键字,还是其他一些语言功能?或者这是不可能的?不幸的是,不可能重构算法,以便我可以延迟所有对象的实例化,直到所有值都已知。如果需要此方案的示例,请考虑每端的不可变对象的双向关系。
答案 0 :(得分:3)
只需将行为封装在自己的类型中:
public sealed class OneTimeAssignable<T> where T : class
{
public T Value
{
get
{
return mValue;
}
set
{
if( mValue != null ) throw new InvalidOperationException( "Value can only be assigned once." );
mValue = value;
}
}
private T mValue;
}
现在您可以将它用作属性的支持字段:
class MyClass
{
private readonly OneTimeAssignable<AnotherClass> mReference = new OneTimeAssignable<AnotherClass>();
public AnotherClass Reference
{
get
{
return this.mReference.Value;
}
internal set
{
this.mReference.Value = value;
}
}
}
现在我将它设置为仅适用于引用类型(假设您不希望它们被设置为null
),但它很容易将其修改为也接受值类型,但需要添加bool
来跟踪属性是否已设置。