2011-03-07 58 views
0

早上好,这是一个不变性的良好实践吗?

假设我有一类

public class Class 
{ 
    int something; 
    int[] otherThing; 
} 

,我想使Class类型不变的对象。再假设我有一个创建Class类型的新对象非常频繁操作,

public Class SomeFunction() 
{ 
    int[] Temp = new int[] { ... }; 

    return new Class(1, Temp); 
} 

为了避免过于频繁地创建新的对象,而且由于Temp不再是该方法的访问,是不是太糟糕设置在构造

this.otherThing = Temp; 

代替

otherThing = new uint[Temp.Length]; 

for (int i = 0; i < Temp.Length; i++) 
{ 
    this.otherThing[i] = Temp[i]; 
} 

非常感谢。

回答

3

如果这样做的构造函数是私有它的罚款IMO。既然你知道另一个数组的内容永远不会改变,你可以直接使用它。如果你想在不引起任何问题的情况下,你甚至可以在你的类的几个实例之间共享一个数组的实例。

另一方面,直接使用提供的数组的公共构造函数是一个坏主意。因为这可以用来打破不变性。

0

区别在于,在第一个选项中,您总是会获得一个新实例,而在第二个选项中,所有创建的“Class”es将指向相同的数组(!)。所以如果你改变任何Class中的数组,所有其他类都会改变。

+0

-1。事实上,我知道这正是我提出这个问题的原因。而且,他们不会指向相同的阵列。它们将指向作为参数传递给构造函数的数组,每次调用该方法时都是新的。 – Miguel 2011-03-07 10:45:29

+0

@Miguel:不,数组是引用类型,所以它们是通过并存储为引用。 – Euphoric 2011-03-07 11:08:54

+0

好,既然你想它是不可变的,我会说你需要一个新的数组(如上所述),除非你100%确定数组不会改变。但是这是一个常量,你不需要每次都通过它。 – Geniedesalpages 2011-03-07 11:46:36

2

最好将temp的副本分配到otherThing,以便对otherThing的任何更改都不会更改temp。您也可以使用Array.CopyTo方法达到此目的。

另外,您应该认真考虑使用IEnumerable<int>IList<int>而不是int[],因为数组天性与不可变性的想法相反。 Read this blog post by Eric Lippert

+0

'otherThing'是一个私人领域。所以没有理由将该字段设为IEnumerable 或IList 。暴露字段时,您需要将其隐藏到“ReadOnlyCollection ”中,或者以隐藏阵列的方式通过“GetEnumerator”。而且由于他可以保证他进场后的阵列在被分配到场后不会改变,所以在没有副本的情况下是安全的。 – CodesInChaos 2011-03-07 10:55:08

+0

虽然这是真的,但为什么从一个数组开始,当一个更安全的数据结构可以完成相同的工作,如IEnumerable 或ReadOnlyCollection 。那么基本上为什么要使用可变数据结构并依赖程序员将其视为不可变的?将来维护\更改此代码的其他开发人员将如何知道该数组应该被视为不可变?为什么不使用不可变的序列呢? – 2011-03-07 11:02:40

+0

你总是假设谁在类中改变代码知道他在做什么。你当然应该证明这个数组是不可变的。而且'IEnumerable '本身就是一个接口,因此既不可变也不可变。这取决于您用于支持界面的集合。 'ReadOnlyCollection '也不是不可改变的。如果你知道'IList '传入它,你仍然可以改变它。 – CodesInChaos 2011-03-07 11:24:33