Tuesday, April 5, 2011

Faster way to clone.

I am trying to optimize a piece of code that clones an object:

#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

Pretty standard stuff. The problem is that the object is pretty beefy and it takes 5.4 seconds (according ANTS Profiler - I am sure there is the profiler overhead, but still).

Is there a better and faster way to clone?

From stackoverflow
    1. Don't implement ICloneable.

    2. The fast way to clone an object is to create a new instance of the same type and copy/clone all fields from the original instance to the new instance. Don't try to come up with a "generic" clone method that can clone any object of any class.

    Example:

    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);
        }
    }
    
    Aaronaught : I agree. I'd also like to add an option (3), use an immutable type so that you don't *need* to clone.
  • As I understand it, streams, even inner ones like this, are expensive.
    Have you tried to just create a new object it and update the relevant fields to bring the object to the same state? I find it hard to believe your method takes less time.

    Guffa : It's rather the reflection used to do the serialisation and deserialisation that is expensive.
  • That's a pretty expensive way to clone. The object never gets on the wire, so all the time doing serialisation is basically wasted. It will be way faster to do memberwise clone. I realise it's not an automagic solution, but it'll be the fastest.

    Something along these lines:

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

0 comments:

Post a Comment