tags:

views:

860

answers:

4

Does anyone want a framework/class which allows me to clone by values .Net objects? I'm only interested with public read/write properties (namely DataContracts), and I don't care if references are resolved correctly (i.e. collecions which contains the same instance of item twice).

I tried serialization trick via DataContractSerializer (serialize to XML and back), wrote redlection-based cloning class (sometimes faster/sometimes slower), and was wondering if someone wrote a helper class which can do this via Emit and not reflection. As for now emitting IL is a little to much for my little brain, but I guess this would be the ultimate solution. Unless someone knows an alternative method which is faster than DataContractSerializer.

Many thanks, Karol

+2  A: 

Try AutoMapper or BLToolkit Mapping

Anton Gogolev
+1  A: 

Dynamic Method based serialization will be fastest. (Generate a dynamic method using light weight codegen and use it for serialization)

You can do 1 method per property/field or one method for the whole object. From my benchmarking doing 1 per property does not give you too much of a performance hit.

See the following code, to see how I do this in Media Browser: http://code.google.com/p/videobrowser/source/browse/trunk/MediaBrowser/Library/Persistance/Serializer.cs

There are also some unit tests there.

There is fast reflection sample on theinstructionlimit that does exactly what you want.

see:

http://theinstructionlimit.com/?p=76

Sam Saffron
A: 

I don't know whether this suits your requirements exactly, but you could also create a deep clone using a BinaryFormatter. See this answer to a related question (by Binoj Antony):

public static class GenericCopier<T>
{
    public static T DeepCopy(object objectToCopy)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, objectToCopy);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return (T) binaryFormatter.Deserialize(memoryStream);
        }
    }
}
0xA3
this is considerably slower than dynamic method based serialization. (about 10x slower at least)
Sam Saffron
@sambo99: Is there a performance comparison available? I only found one comparing standard serialization methods (http://developers.de/blogs/damir_dobric/archive/2007/08/05/performance-comparison-of-most-popular-serializes.aspx)
0xA3
@divo see: http://code.google.com/p/protobuf-net/wiki/Performance .. Marc uses Dynamic Method based serialization in protobuf .net
Sam Saffron
+4  A: 

If you are talking about an object tree/graph:

Writing specific IL to serialize an object is tricky. IMO, your best bet is to look at a full serialization, like how DataContractSerializer would work - but not necessarily with that engine.

For example, protobuf-net has a Serializer.DeepClone<T> method that might help. It should be faster than DataContractSerializer, at least. At the current time, you need to add some clues for the serializer (even if just [ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]) - however, the current (incomplete) work-in-progress offers POCO support without attributes.


If you are talking about individual objects:

There are fairly simple things you can do here with Expression in .NET 3.5; build a dynamic Expression based on reflection, and call .Compile(). MiscUtil has this already:

DestType clone = PropertyCopy<DestType>.CopyFrom(original);

With .NET 2.0/3.0 (without Expression) you might consider HyperDescriptor for similar purposes.

Marc Gravell
Ok, so far I've tested AutoMapper which is actually 4 times slower than DataContract serialization, fast reflections from The Instruction Limit suggested by sambo99 are 2 times faster and protobuf is 3 times faster than DataContract. Marc, can you please elaborate on this: "the current (incomplete) work-in-progress offers POCO support without attributes." I cannot make it work without ProtoContract from featured version of protobuf. Thanks.
Karol Kolenda
I did say it was incomplete! Basically, the "lessgenerics" branch (which doesn't work yet; don't try it) has a separate mechanism for defining the members, etc - obviously *defaulting* to attributes as the fallback. So *at some future point* you would be able to use a closed source type by saying "treat this type like so..." - a bit like the massively overloaded ctor to XmlSerializer.
Marc Gravell
Actually, if your data-contract specifies the Order on each member, then it will use [DataContract]/[DataMember] happily...
Marc Gravell
Yes, I read this in protobuf documentation but it somehow does not work. I mean when I don't specify anything I've got an exception that contract is necessary. When I specified DataContract/DataMember a new object is created but nothing is copied. When use [ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]) everything works as expected. I'm puzzled.
Karol Kolenda
Sorry Marc, didn't notice your remark about Order. Everything works fine.
Karol Kolenda