【问题标题】:Faster way to clone更快的克隆方式
【发布时间】:2010-05-06 22:33:35
【问题描述】:

我正在尝试优化一段克隆对象的代码:

#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 - 我确信有分析器开销,但仍然存在)。

有没有更好更快的克隆方式?

【问题讨论】:

标签: c# .net performance .net-2.0 cloning


【解决方案1】:
  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),使用不可变类型,这样您就不需要需要进行克隆。
  • 使用CGbR 可以得到相同的结果,而无需自己编写代码。
  • 这个解决方案的问题是克隆仍然引用原始属性。因此,对克隆的更改会反映在原版上
【解决方案2】:

答案:有更好的克隆方法。

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

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

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

要使用扩展方法,将文件 DeepCopyByExppressionTrees.cs 放在解决方案中的任何位置就足够了。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 这是相当昂贵的用于进行序列化和反序列化的反射。
    【解决方案4】:

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

    类似的东西:

    class SuperDuperClassWithLotsAndLotsOfProperties {
      object Clone() {
        return new SuperDuperClassWithLotsAndLotsOfProperties {
          Property1 = Property1,
          Property2 = Property2,
        }
    
      public string Property1 {get;set;}
      public string Property2 {get;set;}
      }
    }
    

    【讨论】:

      【解决方案5】:

      因为手动复制字段是我创建代码生成器的最快方式,它会读取您的类定义并生成克隆方法。您只需要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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2010-10-25
        • 2012-02-29
        • 2015-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多