2010-05-06 207 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您的解決方案中的任何地方。