2010-03-10 4 views
6

En utilisant ce code pour sérialiser un objet:Clone objet entier graphique

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); 
    } 
} 

Je l'ai remarqué qu'il ne copie pas les relations. Y a-t-il un moyen d'y arriver?

+0

Je remarqué la même chose, il peut y avoir quelques niveaux, mais la plupart du temps vous vous retrouvez avec un graphique partiel et inutile. – leppie

+0

@leppie - cela peut être fait, cependant ;-p –

Répondre

16

utiliser simplement la surcharge du constructeur qui accepte preserveObjectReferences, et la mettre à 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; } 
} 
+0

Duh! J'aurais dû chercher plus de conseils! :) – leppie

+0

Cela devrait être la meilleure façon que je peux voir ... merci Marc, mais j'ai un problème avec Object.Object2.Object3, cela peut-il être un problème sur le Serializer? –

1

Annotez vos classes avec [DataContract] ou ajoutez vos types enfants dans le constructeur de DatacontractSerializer.

var knownTypes = new List<Type> {typeof(Class1), typeof(Class2), ..etc..}; 
var serializer = new DataContractSerializer(GetType(), knownTypes); 
+0

Thanx, cela semble fonctionner aussi;) –

0

Vous avez besoin d'un sérialiseur binaire pour préserver l'identité des objets lors de l'étape de sérialisation/désérialisation.

+0

Oui, mais j'utilise SqlMetal pour créer les classes et le déclencheur/sérialisation: Unidirectionnel. Désolé pour le dérangement. –

+0

Je ne peux pas comprendre comment votre commentaire est lié à ma réponse ...? Regardez l'exemple de code fourni par Darin Dimitrov – Seb

+1

Désolé @Seb, mais ce n'est pas correct. DataContractSerializer * peut * copier les graphiques appropriés et n'est pas un sérialiseur binaire. Inversement, il n'est pas vrai que tous les sérialiseurs binaires * peuvent * nécessairement copier des graphes. Le support graphique et la sortie binaire sont des concepts orthogonaux. –

1

Pour réaliser un clone profond, vous pouvez envisager d'utiliser un sérialiseur binaire:

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); 
    } 
}