更快的克隆方式

时间:2010-05-06 22:33:35

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

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

#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 - 我确信有探查器开销,但仍然)。

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

5 个答案:

答案 0 :(得分:6)

  1. 不要实施ICloneable。

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

  3. 示例:

    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);
        }
    }
    

答案 1 :(得分:1)

据我所知,溪流,甚至是像这样的内流都很贵 您是否尝试过创建新对象并更新相关字段以使对象处于相同状态?我发现很难相信你的方法花费的时间更少。

答案 2 :(得分:1)

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

这些方面的东西:

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

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

答案 3 :(得分: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;
    }
}

答案 4 :(得分:0)

答:有更好的克隆方法。

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

enter image description here

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

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

要使用扩展方法,只需在解决方案中的任何位置放置 DeepCopyByExptressionTrees.cs 文件即可。