5

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

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

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

4

5 回答 5

7
  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);
    }
}
于 2010-05-06T22:36:18.577 回答
2

答:有更好的克隆方法。

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

在此处输入图像描述

如果您将此链接克隆功能用作扩展方法,则您的每个克隆代码都会缩小到

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

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

于 2016-08-03T07:10:39.213 回答
1

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

于 2010-05-06T22:37:42.457 回答
1

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

这些方面的东西:

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

  public string Property1 {get;set;}
  public string Property2 {get;set;}
  }
}
于 2010-05-06T22:38:05.493 回答
1

因为手动复制字段是我创建代码生成器的最快方式,它读取您的类定义并生成克隆方法。您所需要的只是CGbR nuget 包和实现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;
    }
}
于 2016-05-29T18:33:00.243 回答