Readonly属性集代码在几个构造函数中重复

时间:2014-07-06 14:18:42

标签: c# constructor immutability readonly readonly-collection

我有一个DataStructure类,我希望它是不可变的。

通常,我只是确保我的所有成员都被定义为readonly - 完成工作。 但其中一个成员是一个(整数)列表,所以我需要确保List无法修改;所以我把它改成ReadOnlyCollection<T>。细

我还需要以某种方式对该集合进行排序 - 再次没问题,我在通过.AsReadOnly()进行转换之前对列表进行相应的排序。

到目前为止,一切都很好。

但最后一步是我需要3个不同的构造函数 - 每个构造函数都以不同的格式接受原始数据。 现在我必须在每个构造函数中复制将列表转换为必要格式的代码。

如果我将其归结为setList()方法,则该变量不能为readonly,因为它是在非构造函数方法中分配的。现在我已经失去了一些不变性。

理想情况下,我可以通过某种方式声明setList方法只能从构造函数中调用,因此可以编辑readonly成员,但我不认为存在。

我可以在getter等中创建包装所有内容,这样该类从外部是不可变的,但我更喜欢它从内部也是不可变的(特别是考虑到我可以实现这一点,我牺牲了DRYness )

有没有人对我忘记的语言功能有任何聪明的想法可以解决这个问题?

2 个答案:

答案 0 :(得分:2)

您可以拥有void SetList(List),而不是使用从构造函数调用的List PrepareList(List)。此方法将准备列表,并将其返回给调用者-ie:构造函数。

所以代码不会重复 - 除了每个构造函数中的一个做法_list = PrepareList(list)

答案 1 :(得分:0)

您可以将它作为普通列表保留在您的类中,但只能将其作为只读方式暴露给外部(只需在属性中返回.AsReadOnly())。

虽然如果您确定需要内部不变性,构造函数可以相互调用:

public Foo( int a ) { ... }
public Foo( string a ) : this( int.Parse( a ) ) { ... }

因此,您可以将大部分代码放在一个构造函数中(如果需要,甚至是私有代码),并在其他构建器中完成转换。编辑:以这种方式做很多工作有点困难,所以我仍然认为你应该将转换转移到方法中。如果该方法不访问任何类成员,它仍然是内部不可变的。

我个人更喜欢的另一种模式(即使它只是语法上的不同)是:

private Foo( int a ) { ... }

public static Foo FromBar( Bar b )
{
    int x;
    // convert from Bar here
    return new Foo( x );
}

public static Foo FromSomethingElse( SomeThingElse b )
{
    int x;
    // convert from SomeThingElse here
    return new Foo( x );
}