views:

195

answers:

4

While using for an object this code to serialize it:

        public object Clone()
    {
        var serializer = new DataContractSerializer(GetType());
        using (var ms = new System.IO.MemoryStream())
        {
            serializer.WriteObject(ms, this);
            ms.Position = 0;
            return serializer.ReadObject(ms);
        }
    }

I have noticed that it don't copy the relations!!! Is there any way to make this happen?

+1  A: 

Either annotate your classes with [DataContract] or add your child types in the constructor of DatacontractSerializer.

var knownTypes = new List<Type> {typeof(Class1), typeof(Class2), ..etc..};
var serializer = new DataContractSerializer(GetType(), knownTypes);
Mikael Svenson
Thanx, this looks working too ;)
A: 

You need a binary serializer to preserve objects identity during the serialization/deserialization step.

Seb
Yes, but i use SqlMetal to create the classes and the trigger /serialization:Unidirectional. Sorry for inconvenience.
I can't understand how your comment is related to my answer...? Look at the code sample provided by Darin Dimitrov
Seb
Sorry @Seb, but that is not correct. DataContractSerializer *can* copy proper graphs, and is not a binary serializer. Conversely, it is not true that all binary serializers *can* necessarily copy graphs. Graph support and binary output are orthogonal concepts.
Marc Gravell
@Marc I thought that XmlSerialization wouldn't ever manage to preserve object identity. Am I wrong ? In that case how can I do it ? [I'm used to work with .NET 2.0 but I'm new to 3.0 and haven't yet worked on 3.5, please be gentle ;-)]
Seb
+1  A: 

To perform a deep clone you might consider using a binary serializer:

public static object CloneObject(object obj)
{
    using (var memStream = new MemoryStream())
    {
        var binaryFormatter = new BinaryFormatter(
             null, 
             new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, obj);
        memStream.Seek(0, SeekOrigin.Begin);
        return binaryFormatter.Deserialize(memStream);
    }
}
Darin Dimitrov
+2  A: 

Simply use the constructor overload that accepts preserveObjectReferences, and set it to true:

using System;
using System.Runtime.Serialization;

static class Program
{
    public static T Clone<T>(T obj) where T : class
    {
        var serializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, true, null);
        using (var ms = new System.IO.MemoryStream())
        {
            serializer.WriteObject(ms, obj);
            ms.Position = 0;
            return (T)serializer.ReadObject(ms);
        }
    }
    static void Main()
    {
        Foo foo = new Foo();
        Bar bar = new Bar();
        foo.Bar = bar;
        bar.Foo = foo; // nice cyclic graph

        Foo clone = Clone(foo);
        Console.WriteLine(foo != clone); //true - new object
        Console.WriteLine(clone.Bar.Foo == clone); // true; copied graph

    }
}
[DataContract]
class Foo
{
    [DataMember]
    public Bar Bar { get; set; }
}
[DataContract]
class Bar
{
    [DataMember]
    public Foo Foo { get; set; }
}
Marc Gravell
Duh! I should have looked for more hints! :)
leppie
This should be the best way as i can see...thanx Marc, but i have an issue with Object.Object2.Object3, can this be problem on the Serializer?