【问题标题】:Object cloning in c# [duplicate]c#中的对象克隆[重复]
【发布时间】:2012-04-01 11:54:12
【问题描述】:

考虑这个相关问题:Deep cloning objects

这真的是克隆对象的最佳方式吗? (序列化/反序列化)。序列化对我来说似乎有点贵。

我的想法是创建第二个构造函数并分配所有变量。这种方法会更快吗?

class Test
{

public Test(Test clone)
{
// clone ....
}
}

【问题讨论】:

  • 链接的答案开始提到ICloneable,并且只提到不能使用的序列化。你跳过第一句话了吗?
  • 你问错问题了。问题应该是“哪种途径可以带来更易于维护的代码,这种途径是否会在我的应用程序中引入性能瓶颈”?

标签: c# object clone


【解决方案1】:

这取决于您要克隆什么以及为什么要克隆。如果浅克隆没问题,那么:

private static T CloneShallow<T>(T i) {
    return
        (T)i.GetType()
            .GetMethod(
                "MemberwiseClone",
                BindingFlags.Instance | BindingFlags.NonPublic
            ).Invoke(i, null);
}

这是克隆任何类型的简单记录的最快方法。

如果您需要完整副本,但时间要求不高,那么:

private static T CloneFull<T>(T i) {
    if (Object.ReferenceEquals(i, null)) return default(T);
    var x = new XmlSerializer(i.GetType());
    using (var m = new MemoryStream()) {
        x.Serialize(m, i);
        m.Seek(0, SeekOrigin.Begin);
        return (T)x.Deserialize(m);
    }
}

第二个比第一个慢大约 70 倍。

如果您需要完整复制并且速度很重要,请考虑使用protobuf-net 作为序列化程序。

有很多答案涉及修改您希望克隆的对象,但通常您只需要克隆一个简单的记录,而您不想在其上实现任何东西。

如果您想知道 CloneFull() 有多慢 - 在我的计算机 (i5 661 @ 3.33GHz) 上,记录非常简单,它需要 360 个滴答声,即 36ns。在大多数情况下这已经足够快了:)

【讨论】:

    【解决方案2】:

    序列化对于存储您想稍后/在其他地方检索的对象的表示特别有用。如果您希望对象能够克隆,则应该实现一个 ICloneable 接口。

    【讨论】:

    【解决方案3】:

    如果您正在谈论使用自定义类,最好的方法是实现ICloneable。这样你的类就可以提供一种标准化的方式来克隆自己。

    有时使用“复制构造函数”会更好,但通常只有在您可以看到它很简单并且ICloneable 不能充分满足您的需求时。

    【讨论】:

    【解决方案4】:

    您所指的问题是关于通用克隆,它适用于任何支持序列化的东西。当您只想为您的特定对象进行克隆时,只需实现ICloneable

    class Test : ICloneable {
        public object Clone() {
            // clone ....
        }
    }
    

    【讨论】:

    • @RowlandShaw 是的,确实不鼓励使用ICloneable,因为合约没有指定接口建议的克隆类型。但是,OP 建议使用“复制构造函数” - 克隆风格,通常根本不算作克隆。在比较这两个想法时,使用ICloneable 听起来更可取。
    • ...只要您能保证所有子对象都支持克隆到同一个合约。我必须承认我倾向于实现一个复制构造函数,并让Clone 调用它;在继承层次结构中也可以更容易处理。沿着序列化/反序列化路线走下去可能会导致真正糟糕的性能问题。
    • Clone() 无论如何都需要调用构造函数,而无需添加构造函数无法执行的任何操作。最好避免 Clone() 不必要的开销,并有一个专门用于克隆的构造函数,如public MyClass(MyClass original): this(/*pass all properties here*/) {}
    【解决方案5】:

    关键词在accepted answer

    好处是当对象变得过于复杂时,您不必担心克隆所有内容。

    序列化方法适用于任何复杂性的任何对象。虽然对于更小、更简单的对象来说,这可能是矫枉过正,但它是一个可扩展的解决方案。

    如果您知道您的对象不会改变并且您只想克隆简单的对象,那么您的方法是完全可以接受的。虽然实现ICloneable 接口是首选解决方案。

    【讨论】:

      【解决方案6】:

      ICloneable

      引用:

      支持克隆,它创建一个与现有实例具有相同值的类的新实例。 ICloneable 接口包含一个成员 Clone,它旨在支持超出 MemberwiseClone 提供的克隆。有关克隆、深拷贝和浅拷贝以及示例的详细信息,请参阅 Object.MemberwiseClone 方法。

      【讨论】:

      • @Rowland Shaw 为什么????
      • 因为界面没有明确说明消费者应该期待浅克隆还是深克隆;这是一个实施选择。这被认为没有帮助。
      猜你喜欢
      • 2014-07-08
      • 2017-06-13
      • 2014-01-11
      • 2011-02-04
      • 2013-04-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多