2013-04-30 84 views
0

我最初创建了一个不是不可变的类,但是现在我想要选择创建一个不可变的等价数据结构。假设,例如,可变类:将对象转换为不可变

namespace Utility 
{ 
    public class bar 
    { 
     public string name { get; set; } 
     public double weight { get; set; } 
     public int age { get; set;} 
     public List<...> friendInstances; //instantiated at run time 
    } 
} 

    //and now I make a mutable class. 

public class MemorySafe_bar 
{ 
    private readonly string _name; 
    private readonly double _weight; 
    private readonly int _age; 
    private readonly List<...> _friendInstances; 

    public MemorySafe_bar(string name, double weight, int age, 
     List<...> friend Inst) 
    { 
     _name = name; 
     _weight = weight; 
     _age = age; 
     _friendInstances = Inst 
    } 
    //..getters would go here... 

    function() 
    { 
     Utility.bar bar_ex = new bar(); 
     bar_ex.name = "Kathy"; 
     bar_ex.weight = 42.34; 
     bar_ex.age = 10; 
     bar_ex.List<...> friends = new List<...>(); 
     friends.Add(stuff); 

     Utility.MemorySafe_bar = new MemorySafe_bar(
     bar_ex.name, bar_ex.weight, bar_ex.age, friends); 
    } 
} 

我不相信这个可变对象在将来会从此改变。

+0

你究竟想要解释什么?为什么不用静态构造函数设置一个静态类? – Nomad101 2013-04-30 01:04:02

+1

试图格式化您的代码,但有一个奇怪的'功能()'范围不明确 - 请更新代码...也添加问题的帖子。 – 2013-04-30 01:04:50

+3

问题是什么?另外,如果一个对象被认为是不可变的,它的所有成员也必须是不可变的,这意味着你不能使用'List'。 – svick 2013-04-30 01:10:46

回答

2

如果您要求提供一种通用/可重复使用的方法来包装任何类为不可变版本,但它在一般意义上并不可行。

如果一个特定的类暴露了其成员virtualabstract(或作为interface),你可以创建是什么也不做(或抛出异常)的setter方法实现,但这通常是意想不到的。

在你目前的情况下,我会首先更新构造函数以获取包装对象,或者通过静态工厂方法来实现。我还要保存friendInstances的本地副本,并返回一个只读枚举它:

public class ReadOnlyBar 
{ 
    public string name { get; private set; } 
    public double weight { get; private set; } 
    public int age { get; private set; } 

    private readonly Friend[] _friendInstances; 

    public IEnumerable<Friend> friendInstances 
    { 
     get 
     { 
      foreach(var friend in _friendInstances) 
       yield return friend; 
     } 
    } 

    public ReadOnlyBar(Bar bar) 
    { 
     this.name = bar.name; 
     this.weight = bar.weight; 
     this.age = bar.age; 
     this._friendInstances = bar.friendInstances.ToArray(); 
    } 
} 

用法,如:

Bar mutableBar = new mutableBar() { name="Kathy", .... }; 
ReadOnlyBar readonlyBar = new ReadOnlyBar(mutableBar); 

我只用简单的属性,而不是readonly领域保持不变酒吧尽可能匹配原始的Bar的API;这些可以很容易地切换回字段(这将有助于强化对类中的骨头编码的不变性)。您也可以轻松地移动创建静态工厂方法或扩展方法,所以你可能会得到这样的用法:

Bar mutableBar = new mutableBar() { name="Kathy", .... }; 
ReadOnlyBar readonlyBar = ReadOnlyBar.Create(mutableBar); 
//or 
ReadOnlyBar readonlyBar = mutableBar.MakeReadOnly(); 

编辑:另一种快速的选择,如果你想保持大部分List<Friend>功能/成员,而不是降低它到IEnumerable,你也可以使用这样的:

public ReadOnlyCollection<Friend> friendInstances { get; private set; } 

public ReadOnlyBar(Bar bar) 
{ 
    //other initialization 
    this.friendInstances = bar.friendInstances.ToList().AsReadOnly(); 
} 

或者你甚至可以类型是List<Friend>并在吸气返回内部列表的副本,但是这可能会有点远,是一个令人困惑财产暴露在“不可变”的对象类型上。