6
votes

Graphique d'objet entier clone

Lorsque vous utilisez ce code pour sérialiser un objet:

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


2 commentaires

J'ai remarqué la même chose, cela pourrait aller quelques niveaux, mais surtout vous vous retrouvez avec un graphique partiel et inutile.


@Leppie - cela peut être fait, cependant ;-p


4 Réponses :


1
votes

soit annotant vos classes avec [Datacontract] code> ou ajoutez vos types d'enfants dans le constructeur de DatacontractSerializer.

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


0 commentaires

0
votes

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


4 commentaires

Oui, mais j'utilise SQLMetal pour créer les classes et la gâchette / la sérialisation: unidirectionnel. Désolé pour la gêne occasionnée.


Je ne comprends pas comment votre commentaire est lié à ma réponse ...? Regardez l'échantillon de code fourni par Darin Dimitrov


Désolé @seb, mais ce n'est pas correct. DatacontractSerializer peut Copier des graphiques appropriés et n'est pas un sérialiseur binaire. Inversement, il n'est pas vrai que tous les sérialiszers binaires peuvent copier nécessairement des graphiques. Le support graphique et la production binaire sont des concepts orthogonaux.


@MARC Je pensais que la xmlserialisation ne parviendrait jamais à préserver l'identité d'objet. Ai-je tort ? Dans ce cas, comment puis-je le faire? [Je suis habitué à travailler avec .net 2.0 mais je suis nouveau à 3.0 et je n'ai pas encore travaillé sur 3,5, s'il vous plaît soyez doux ;-)]



1
votes

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


0 commentaires

16
votes

Utilisez simplement la surcharge du constructeur qui accepte preserveobjectReferences code>, et définissez-la sur 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; }
}


2 commentaires

Duh! J'aurais dû chercher plus de notes! :)


Cela devrait être le meilleur moyen que je puisse voir ... merci Marc, mais j'ai un problème avec objet.Object2.Object3, peut-il être un problème sur le sérialisateur?