.Net深度克隆 - 最佳方法是什么?

11

我需要对我的复杂对象模型执行深度克隆。在.Net中,你认为最好的方法是什么?
我考虑过序列化/反序列化
不需要提到MemberwiseClone不够好。


4
请注意:这确实是您想表达的意思吗?对象之间的循环引用可能会导致深度克隆出现问题,应当非常谨慎。 - Jeremy McGee
这个可以实现深度克隆,而不需要序列化:http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home - Omu
UltraMapper https://www.nuget.org/packages/UltraMapper/ - Mauro Sampietro
7个回答

15
如果您控制对象模型,那么您可以编写代码来实现,但这将需要大量维护。然而,存在许多问题,这意味着除非您绝对需要最快的性能,否则序列化通常是最易于管理的答案。
这是其中一个情况,其中BinaryFormatter可起到可接受的作用;通常情况下,我不是它的粉丝(由于版本控制等问题),但由于序列化数据是为了即时使用,这不是一个问题。
如果您希望它更快一点(但没有自己的代码),那么protobuf-net可能有所帮助,但需要进行代码更改(添加必要的元数据等)。并且它是基于树结构(而不是图形结构)的。
其他序列化程序(XmlSerializer,DataContractSerializer)也很好,但如果仅用于克隆,则它们可能在BinaryFormatter方面没有太多优势(除了XmlSerializer不需要[Serializable])。
因此,这实际上取决于您的确切类和场景。

也许提供一个示例链接会更好。我正在使用UWP,无法使用BinaryFormatter。Marty提供了XML序列化器。我对DataContractSerializer和protobuf-net很感兴趣。 - Syaiful Nizam Yahya

10

如果您正在运行部分受信任的环境(例如Rackspace Cloud),则可能受限于使用BinaryFormatter。可以改用XmlSerializer。

public static T DeepClone<T>(T obj)
{
    using (var ms = new MemoryStream())
    {
        XmlSerializer xs = new XmlSerializer(typeof(T));
        xs.Serialize(ms, obj);
        ms.Position = 0;

        return (T)xs.Deserialize(ms);
    }
}

当克隆对象的某些属性为接口(例如IEnumerable,IList等)时,无法正常工作。会抛出异常。 - Ofer Zelig

5

来自msdn杂志的深度克隆示例:

    Object DeepClone(Object original)
    {
        // Construct a temporary memory stream
        MemoryStream stream = new MemoryStream();

        // Construct a serialization formatter that does all the hard work
        BinaryFormatter formatter = new BinaryFormatter();

        // This line is explained in the "Streaming Contexts" section
        formatter.Context = new StreamingContext(StreamingContextStates.Clone);

        // Serialize the object graph into the memory stream
        formatter.Serialize(stream, original);

        // Seek back to the start of the memory stream before deserializing
        stream.Position = 0;

        // Deserialize the graph into a new set of objects
        // and return the root of the graph (deep copy) to the caller
        return (formatter.Deserialize(stream));
    }

1

0

手动实现是最好的方式。这样会比任何其他通用方法都更快。此外,还有很多关于这个操作的库(你可以在这里看到一些带有性能基准的列表)。

顺便说一句,BinaryFormatter对于这个任务非常慢,只适合于测试。


0

最好的方法可能是在你的对象及其所有需要自定义深度克隆功能的字段中实现System.ICloneable接口。然后,你实现Clone方法以返回你的对象及其成员的深层副本。


2
仍然有人反对这种做法,我也同意他们的看法。在一个对象上使用IClonable可能意味着深度复制,而在另一个对象上则是浅复制。在进行调用时无法区分。当然,这并不完全适用于内部项目,但是及早认识到这种不良实践也不是坏事。 - jfsk3

0
你可以尝试使用AltSerialize,它在许多情况下比 .Net 序列化器更快。它还提供了缓存和自定义属性来加速序列化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接