2010-05-06 190 views
4

我试图优化一段代码,克隆的对象:更快的方式克隆

#region ICloneable 
public object Clone() 
{ 
    MemoryStream buffer = new MemoryStream(); 
    BinaryFormatter formatter = new BinaryFormatter(); 

    formatter.Serialize(buffer, this);  // takes 3.2 seconds 
    buffer.Position = 0; 
    return formatter.Deserialize(buffer); // takes 2.1 seconds 
} 
#endregion 

漂亮的标准的东西。问题是这个对象非常强壮,需要5.4秒(根据ANTS Profiler-我确定有分析器开销,但仍然)。

有更好更快的克隆方法吗?

+0

这完全取决于你想克隆的东西。 – 2010-05-06 22:35:09

+0

另请参阅http://stackoverflow.com/questions/852064/faster-deep-cloning – nawfal 2013-05-12 04:46:19

回答

6
  1. 请勿实施ICloneable。

  2. 克隆对象的快速方法是创建一个相同类型的新实例,并将所有字段从原始实例复制/克隆到新实例。不要试图想出一个可以克隆任何类的任何对象的“通用”克隆方法。

实施例:

class Person 
{ 
    private string firstname; 
    private string lastname; 
    private int age; 

    public Person(string firstname, string lastname, int age) 
    { 
     this.firstname = firstname; 
     this.lastname = lastname; 
     this.age = age; 
    } 

    public Person Clone() 
    { 
     return new Person(this.firstname, this.lastname, this.age); 
    } 
} 
+3

我同意。我还想添加一个选项(3),使用不可变类型,以便不需要*克隆。 – Aaronaught 2010-05-06 22:40:44

+0

使用[CGbR](https://github.com/Toxantron/CGbR)可以为您提供相同的结果,而无需自己编写代码。 – Toxantron 2016-05-29 18:24:12

1

据我所知,溪流,甚至那些内这样,是昂贵的。
您是否尝试过创建一个新对象并更新相关字段以使对象处于相同状态?我很难相信你的方法需要更少的时间。

+0

这是用来执行昂贵的序列化和反序列化的反射。 – Guffa 2010-05-06 22:44:32

1

这是一个非常昂贵的克隆方式。对象永远不会上网,所以所有的时间序列化基本上都浪费了。成员克隆将会更快。我意识到这不是一个automagic解决方案,但它会是最快的。

东西沿着这些路线:

class SuperDuperClassWithLotsAndLotsOfProperties { 
    object Clone() { 
    return new SuperDuperClassWithLotsAndLotsOfProperties { 
     Property1 = Property1, 
     Property2 = Property2, 
    } 

    public string Property1 {get;set;} 
    public string Property2 {get;set;} 
    } 
} 
1

因为手动复制领域,是我创建了一个代码生成器以最快的方式,读取你的类定义和生成的克隆方法。所有你需要的是CGbR nuget package和实现ICloneable的部分类。发电机将完成其余的工作。

public partial class Root : ICloneable 
{ 
    public Root(int number) 
    { 
     _number = number; 
    } 
    private int _number; 

    public Partial[] Partials { get; set; } 

    public IList<ulong> Numbers { get; set; } 

    public object Clone() 
    { 
     return Clone(true); 
    } 

    private Root() 
    { 
    } 
} 

public partial class Root 
{ 
    public Root Clone(bool deep) 
    { 
     var copy = new Root(); 
     // All value types can be simply copied 
     copy._number = _number; 
     if (deep) 
     { 
      // In a deep clone the references are cloned 
      var tempPartials = new Partial[Partials.Length]; 
      for (var i = 0; i < Partials.Length; i++) 
      { 
       var value = Partials[i]; 
       value = value.Clone(true); 
       tempPartials[i] = value; 
      } 
      copy.Partials = tempPartials; 
      var tempNumbers = new List<ulong>(Numbers.Count); 
      for (var i = 0; i < Numbers.Count; i++) 
      { 
       var value = Numbers[i]; 
       tempNumbers[i] = value; 
      } 
      copy.Numbers = tempNumbers; 
     } 
     else 
     { 
      // In a shallow clone only references are copied 
      copy.Partials = Partials; 
      copy.Numbers = Numbers; 
     } 
     return copy; 
    } 
} 

和部分类

public partial class Partial : ICloneable 
{ 
    public short Id { get; set; } 

    public string Name { get; set; } 

    public object Clone() 
    { 
     return Clone(true); 
    } 
} 

public partial class Partial 
{ 
    public Partial Clone(bool deep) 
    { 
     var copy = new Partial(); 
     // All value types can be simply copied 
     copy.Id = Id; 
     copy.Name = Name; 
     return copy; 
    } 
} 
0

答:对于克隆的更好的方法。

反射表达式树快得多然后序列化(反射是5倍更快,表达式树是快20倍)。

enter image description here

如果使用this linked cloning function作为一个扩展方法,每个克隆代码缩小到

#region ICloneable 
public object Clone() 
{ 
    return this.DeepCopyByExpressionTree(); 
} 
#endregion 

要使用的扩展方法是足有文件DeepCopyByExptressionTrees。cs您的解决方案中的任何地方。