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);
    }
}

从现在开始,我不相信可变对象将来会被更改。

4

1 回答 1

2

如果您要求将任何类包装为不可变版本的通用/可重用方法,那么从一般意义上讲,这实际上是不可能的。

如果一个特定的类将其成员公开为virtualor abstract(或作为 an 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);

我只使用属性而不是字段来保留不可变的 Bar ,以尽可能readonly地匹配原始的 API;Bar这些可以很容易地切换回字段(这将有助于对类中的愚蠢编码实施不变性)。您还可以轻松地将创建移动到静态工厂方法或扩展方法,因此您可能会得到如下用法:

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();
}

或者您甚至可以键入 is asList<Friend>并在 getter 中返回内部列表的副本,但这可能有点远,并且是在“不可变”对象类型上公开的令人困惑的属性。

于 2013-04-30T02:01:14.857 回答