我终于设法复制了我的对象的值类型,一个使用字典来存储动态属性的类。我想知道两件事,单声道兼容性和效率。我是C#的新手,并且仍然有很多关于编程的知识,所以如果我滥用了几个短语就道歉:P
我使用此方法How do you do a deep copy of an object in .NET (C# specifically)? ...来复制我的对象。 我也会有数百个这样的对象,并且想知道以这种方式复制它们是非常低效的吗?结构会是更好的选择吗?但我不确定何时使用结构。它可以用单声道移植吗?一些谷歌搜索表明这种序列化可能会引发问题。
答案 0 :(得分:3)
根据评论中的后续回复,您正在寻找的最佳解决方案是最简单的方法:编写代码以自行复制对象。
如果您的类与存储自定义属性的键/值对的字典的包装器一样简单,则可以使用Dictionary(IDictionary)构造函数将值从一个字典复制到另一个字典。
class MyWrapper
{
private Dictionary<string, object> properties =
new Dictionary<string, object>();
public MyWrapper Clone()
{
MyWrapper output = new MyWrapper();
output.properties = new Dictionary<string, object>(properties);
}
}
显然,这是一个简化的类,实际上并没有做任何东西,但是根据你所描述的,这应该可以得到你所需要的东西。没有反思,没有“陷阱”,只是从一个字典到另一个字典的简单值。
我不能说单声道可移植性,因为我是一个仅限Windows的开发人员,但就效率而言,一个明确的解决方案可以复制您需要的内容,而不是基于反射的解决方案。
任何任意类型的真正深层副本的概念都不是在基于引用的面向对象语言中轻松(甚至安全)实现的。虽然简单的类很容易复制,但引用循环,没有无参数构造函数的类和不可变类型都会带来挑战。
例如,考虑这个类:
public class Foo
{
public Foo Next { get; set; }
}
这几乎是单链表的最简单实现。一个简单的深度复制算法将从Foo
的第一个实例开始,然后通过递归地向下导航Next
个引用链来克隆它,直到它遇到null
值。然而,这样做,我们不仅会吃掉内存,而且最终会得到不代表原始实际克隆的对象:
Foo first = new Foo();
first.Next = new Foo();
first.Next.Next = first;
这是完全合法的(甚至是合理的)事情,但现在我们有一个循环的参考循环,它将炸毁我们的天真克隆算法。所以现在我们必须实现一个对象缓存。
Dictionary<object, object> clonedObjects;
现在,在克隆算法中,在为属性或字段分配值时,我们检查缓存以查看是否已经克隆了我们即将复制的引用。如果有,我们使用该值而不是克隆新值。这将为我们提供一个全新的对象图,它代表我们的原始对象,也是一个完整的克隆。太好了吧?
现在,无参数构造函数怎么样?这个甚至在一般意义上都是不可解决的。如果我创建这个类:
public class Bar
{
public Bar(string gotcha) { }
}
没有办法以天真的方式克隆这门课程;因为你无法知道如何来调用构造函数(你可以反射地获得ConstructorInfo
,但是它的调用语义将是完全未知的。你能做的最好的就是存储元数据(通过类的自定义属性)关于调用哪个构造函数以及如何调用它(例如,按照它们应该传递的顺序的字段列表),但这需要先前的克隆知识机制并且还暗示构造函数的参数是原始对象上的字段,但情况不一定如此。
现在我们在混合中引入另一个障碍:不可变引用类型。这个也可能导致意外行为。不可变引用类型是其(外部可见)值不能改变的引用类型;在大多数情况下,这些类旨在展示值类型语义。他们还经常缺乏无参数构造函数(甚至可能根本没有公开可用的构造函数),使他们遭受我们以前的烦恼,但他们也可能使用基于工厂的方法,以便他们可以确保参考平等也意味着价值平等,反之亦然(后一种情况不太常见,但如果我们谈论的算法是一种完全天真的克隆机制,那么我们必须覆盖它)。这再次表示另一个自定义属性,表示克隆机制应该只复制引用而不是克隆实际对象。
因此,简而言之,在处理任意类型时,完全无法使用完全天真的深层复制机制。类型必须在设计时考虑到克隆机制,并且可能必须以特定方式做出让步或装饰自己才能使用它。这与相对不常见的需求相结合,可能就是为什么现在没有框架级深层复制机制,以及为什么你应该考虑一个更明确的复制机制,你知道要复制的内容(以及可能的内容)没关系)所以你可以确定你得到的就是你想要的东西。
答案 1 :(得分:1)
结构具有一些独特的特征,在使用它们之前应该认真考虑。
http://msdn.microsoft.com/en-us/library/aa288471(v=vs.71).aspx
在询问结构是否适合您的情况之前,请考虑这些要点。
我通常会坚持只为我的班级编写一个方法来创建一个深层副本。您可能会真正看中并使用泛型和反射的组合来编写一个非常抽象的DeepClone<T>(T object)
方法。或者走简单的道路,然后写一个适合该课程的裁缝。