Более быстрый способ клонирования - PullRequest
4 голосов
/ 07 мая 2010

Я пытаюсь оптимизировать фрагмент кода, который клонирует объект:

#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 ]

6 голосов
/ 07 мая 2010
  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);
    }
}
1 голос
/ 29 мая 2016

Поскольку ручное копирование полей - это самый быстрый способ, которым я создал генератор кода, он читает определение вашего класса и генерирует метод клонирования. Все, что вам нужно, - это пакет CGbR и частичный класс, реализующий 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;
    }
}
1 голос
/ 07 мая 2010

Это довольно дорогой способ клонирования. Объект никогда не подключается, поэтому все время сериализации в основном теряется. Это будет намного быстрее сделать членское клонирование. Я понимаю, что это не автоматическое решение, но оно будет самым быстрым.

Что-то вроде этого:

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

  public string Property1 {get;set;}
  public string Property2 {get;set;}
  }
}
1 голос
/ 07 мая 2010

Насколько я понимаю, потоки, даже внутренние, как это, дороги.
Вы пытались просто создать новый объект и обновить соответствующие поля, чтобы привести объект в то же состояние? Мне трудно поверить, что ваш метод занимает меньше времени.

0 голосов
/ 03 августа 2016

Ответ: Есть лучшие методы для клонирования.

Отражение или Деревья выражений намного быстрее, чем Сериализация (отражение 5x быстрее , деревья выражений 20x быстрее ).

enter image description here

Если вы используете эту связанную функцию клонирования в качестве метода расширения, каждый ваш код клонирования сжимается до

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

Чтобы использовать метод расширения, достаточно иметь файл DeepCopyByExptressionTrees.cs в любом месте вашего решения.

...