将对象转换为不可变对象
本文关键字:对象 不可变 转换 | 更新日期: 2023-09-27 18:11:20
我最初创建了一个不是不可变的类,但是现在我想要有一个创建不可变等效数据结构的选项。例如,假设有一个可变类:
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);
}
}
我不相信从现在开始可变对象将来会被改变。
如果你想要一个通用的/可重用的方法来包装任何类成为一个不可变的版本,这在一般意义上是不可能的。
如果一个特定的类将其成员公开为virtual
或abstract
(或作为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();
}
或者你甚至可以输入is为List<Friend>
,在getter中返回内部列表的副本,但这可能有点过分了,并且在"不可变"对象类型上暴露是一个令人困惑的属性。