Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to copy dynamic object that does not support copy function

First of all we probably all agree that the best way would be to implement Copy function inside custom object/entity. But consider this scenario. We don't have this option and we don't want to write specific function that will make exact copy of entity because entity will be changed in the future so our copy function would fail.

Here is simplified version of current entity:

[Serializable]
class MyEntity
{
    public MyEntity()
    { 
    }

    public MyEntity(int id, string name)
    {
        this.Id = id;
        this.Name = name; 
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public MyEntity Copy()
    {
        throw new NotImplementedException();
    }
}

To cover all the requirements above I came up with two solutions:

        //original...
        MyEntity original = new MyEntity() { Id = 1, Name = "demo1" };

        //first way to copy object...
        List<MyEntity> list = new List<MyEntity>() { original};
        MyEntity copy1 = list.ConvertAll(entity => new MyEntity(entity.Id, entity.Name))[0];

        //second way to copy object...
        byte[] bytes = SerializeEntity(original);
        MyEntity copy2 = (MyEntity)DeserializeData(bytes);


    byte[] SerializeEntity(object data)
    {
        byte[] result = null;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(ms, data);
            result = ms.ToArray();
        }
        return result;
    }

    object DeserializeData(byte[] data)
    {
        object result = null;
        using(MemoryStream ms = new MemoryStream(data))
        {
           BinaryFormatter formatter = new BinaryFormatter();
           result = formatter.Deserialize(ms); 
        }
        return result;
    }

And now the question. What solution is the most optimal behind the scene and why, first or second? Is there any better way to do exact copy considering requirements above? Copies will be done in large numbers.

PS note: I am aware that first way is basicly already a copy function as Honza pointed out. I am kind of looking something versatile as serialization and near fast as custom copy function.

like image 715
Gregor Primar Avatar asked Dec 23 '12 00:12

Gregor Primar


1 Answers

First of all we probably all agree that the best way would be to implement Copy function inside custom object/entity.

I don't agree. I hate to write such methods every time. Here is my suggestion using an extension method:

public static T Copy<T>(this T obj)
    where T : class
{
    using (MemoryStream stream = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, obj);

        stream.Seek(0, SeekOrigin.Begin);
        return formatter.Deserialize(stream) as T;
    }
}

This is basically your second solution but slightly optimized. There is no need to copy the MemoryStream to a byte array and then create another MemoryStream from that.

The best thing is that it is generic an can be used with every object that has the [Serializable] attribute. And i'm quite sure that it is faster than your first solution where you have to access each property (although I didn't measure).

Edit:

Ok, I actually did some measuring now. My first assumption for the performance was completely wrong!

I created 1000000 MyEntity objects with random values and then copied them (I also considered Honza Brestan's hint on deep and shallow copies):

deep copy with Binary formatter: 14.727 s
deep copy with Copy method: 0.490 s
shallow copy with reflection: 5.499 s
shallow copy with Copy method: 0.144 s

like image 57
pescolino Avatar answered Oct 28 '22 05:10

pescolino