根据评论中的跟进回复,你所寻找的最佳解决方案是最简单的:自己编写代码来复制对象。
如果您的类真的只是一个包装字典的简单类,用于存储自定义属性的键/值对,那么您可以使用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);
}
}
显然,这是一个简化的类,实际上并没有做任何事情,但根据你所描述的,这应该能满足你的需求。没有反射,没有“陷阱”,只是从一个字典中简单地复制值到另一个字典中。
编辑
我无法确定它在mono上的可移植性,因为我只是一个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,但它的调用语义将完全不知道)。最好的方法是存储元数据(通过类上的自定义属性),以了解要调用哪个构造函数以及如何调用它(例如应该传递的字段列表顺序),但这需要先了解克隆机制,并且暗示构造函数的参数是原始对象上的字段,这并不一定是正确的。
现在我们又遇到了另一个问题:不可变引用类型。这也可能导致意外行为。不可变引用类型是指其(外部可见)值不能更改的引用类型;在大多数情况下,这些类被设计为表现出值类型语义。它们也经常缺乏无参构造函数(甚至可能根本没有公共可访问构造函数),从而使它们遭受我们之前的烦恼,但它们也可以使用基于工厂的方法,以便它们可以确保引用相等也意味着值相等,反之亦然(后一种情况较少见,但如果我们谈论的是完全天真的克隆机制,则必须涵盖它)。这又意味着另一个自定义属性,以指示克隆机制应该仅复制引用而不是克隆实际对象。
因此,简单的深度复制机制在处理任意类型时根本不可能。必须设计类型以考虑克隆机制,并且可能需要做出让步或以特定方式装饰自己以使其与之配合。这再加上相对不频繁的需求,很可能是为什么现在没有框架级深度复制机制的原因,以及为什么您应该考虑更明确的复制机制,以便您知道要复制什么(以及什么可能无关紧要),以便确保您得到的就是您想要的。