.Net 深度克隆——最好的方法是啥?

Posted

技术标签:

【中文标题】.Net 深度克隆——最好的方法是啥?【英文标题】:.Net Deep cloning - what is the best way to do that?.Net 深度克隆——最好的方法是什么? 【发布时间】:2010-11-18 02:05:21 【问题描述】:

我需要对我的复杂对象模型执行深度克隆。您认为在 .Net 中实现这一目标的最佳方式是什么? 我想过序列化/反序列化 不用说MemberwiseClone不够好。

【问题讨论】:

要非常小心;这真的是你的意思吗?对象之间的循环引用会很快导致深度克隆出现问题。 这个不用序列化valueinjecter.codeplex.com/… UltraMapper nuget.org/packages/UltraMapper 【参考方案1】:

手动实现此功能的最佳方式。它会比任何其他通用方法都快。此外,还有很多用于此操作的库(您可以查看一些带有性能基准的列表here)。

顺便说一下,BinaryFormatter 对于这个任务来说非常慢,只能用于测试。

【讨论】:

【参考方案2】:

请看好文章C# Object Clone Wars。我在那里找到了一个非常有趣的解决方案:Copyable: A framework for copying or cloning .NET objects

【讨论】:

【参考方案3】:

如果您在 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 等)时不起作用。引发异常。【参考方案4】:

来自 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));
    

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

如果你控制了对象模型,那么你可以写代码来做,但是需要大量的维护。但是有很多问题,这意味着除非您绝对需要最快的性能,否则序列化通常是最易于管理的答案。

这是BinaryFormatter 可以正常工作的情况之一;通常我不是粉丝(由于版本控制等问题) - 但由于序列化数据是为了立即使用,所以这不是问题。

如果您希望它更快一点(但没有您自己的代码),那么protobuf-net 可能会有所帮助,但需要更改代码(添加必要的元数据等)。它是基于树的(不是基于图的)。

其他序列化程序(XmlSerializerDataContractSerializer)也可以,但如果它只是用于克隆,它们可能不会提供太多超过 BinaryFormatter(除非 XmlSerializer 没有不需要[Serializable]

真的,这取决于你的具体课程和场景。

【讨论】:

也许链接到示例可能会很好。我正在使用 UWP,但我不能使用 BinaryFormatter。 XML 序列化器由 Marty 在下面给出。我对 DataContractSerializer 和 protobuf-net 很好奇。【参考方案7】:

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

【讨论】:

仍有一些建议反对这一点,我同意他们的看法。 IClonable 在一个对象上可能意味着很深,而在另一个对象上则很浅。拨打电话时无法辨别。当然,这实际上并不完全适用于内部项目,但尽早识别并不是一个坏习惯。

以上是关于.Net 深度克隆——最好的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 JavaScript 中深度克隆对象的最有效方法是啥?

在 JavaScript 中深度克隆对象的最有效方法是啥?

在 JavaScript 中深度克隆对象的最有效方法是啥?

在 JavaScript 中深度克隆对象的最有效方法是啥?

java中的浅克隆和深克隆是啥

用于深度克隆的单元测试