有没有一个简单的方法来使一个实例不可变?
我们举一个例子,我有一个类持有大量数据字段(仅数据,没有行为):
class MyObject
{
// lots of fields painful to initialize all at once
// so we make fields mutable :
public String Title { get; set; }
public String Author { get; set; }
// ...
}
创作实例:
MyObject CreationExample(String someParameters)
{
var obj = new MyObject
{
Title = "foo"
// lots of fields initialization
};
// even more fields initialization
obj.Author = "bar";
return obj;
}
但是现在我已经完全创建了我的对象,我不想让对象变得可变了(因为数据消费者永远不需要改变状态),所以我想要这样的东西List.AsReadOnly:
var immutableObj = obj.AsReadOnly();
但是如果我想要这个行为,我需要使另一个类具有完全相同的字段,但没有setter.
那么有什么自动的方式来产生这个不可变的类?或者另一种允许在创建过程中发生变异的方式,一旦初始化就可以变得不可
我知道这些字段可以被标记为“只读”,但该对象将被初始化在类之外,并将所有字段作为构造函数传递,似乎是一个坏主意(参数太多).
解决方法
不,没有什么简单的方法可以使任何类型不可变,特别是如果你想要“深度”不变性(即通过不可变对象无法达到可变对象的话).您将不得不明确地将您的类型设计为不可变的.使类型不可变的通常机制是:
>声明(属性支持)字段只读. (或者,从C#6 / Visual Studio 2015开始,使用read-only auto-implemented properties.)
>不要暴露属性设置器,只允许访客.
>为了初始化(属性支持)字段,必须在构造函数中初始化它们.因此,将(property)值传递给构造函数.
>不要暴露可变对象,例如基于可变的默认类型(如T [],List< T>,Dictionary< TKey,TValue等)的集合. 如果需要公开集合,请将其返回到防止修改的包装器中(例如.AsReadOnly()),或者至少返回内部集合的新副本.
>使用Builder模式.以下示例对于执行模式正义来说太小了,因为通常建议在需要创建非平凡对象图的情况下进行;然而,基本的想法是这样的:
class FooBuilder // mutable version used to prepare immutable objects
{
public int X { get; set; }
public List<string> Ys { get; set; }
public Foo Build()
{
return new Foo(x,ys);
}
}
class Foo // immutable version
{
public Foo(int x,List<string> ys)
{
this.x = x;
this.ys = new List<string>(ys); // create a copy,don't use the original
} // since that is beyond our control
private readonly int x;
private readonly List<string> ys;
…
}