有没有一个简单的方法来使一个实例不可变?
我们举一个例子,我有一个类持有大量数据字段(仅数据,没有行为):
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; … }