11 votes

Sérialisation et héritage XML .NET

J'ai une structure comme ça :

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;

La liste contient des objets de type B et C ; ils ont également certains champs que je voudrais conserver. Puis-je maintenant la sérialiser, la désérialiser et obtenir les instances d'objets appropriées ? De préférence en XML

EDITAR:

Existe-t-il un moyen simple de sérialiser cette liste qui contient des interfaces, puis de la désérialiser en instances B et C ?

6voto

jonnii Points 17046

En supposant que vous utilisez la sérialisation XML intégrée de .net, vous devriez examiner l'attribut suivant :

System.Xml.Serialization.XmlIncludeAttribute

Il vous permet de demander au sérialiseur d'inclure d'autres types lors de la sérialisation/désérialisation.

Ajouter de nouveaux types à la liste et ne pas mettre à jour les métadonnées de sérialisation est une source fréquente d'erreurs. Assurez-vous d'avoir une couverture de test adéquate.

5voto

CkH Points 1086

J'utiliserais une classe abstraite au lieu d'une interface (car on ne peut pas sérialiser un type d'interface), puis au lieu de coder en dur le type en utilisant l'attribut XmlInclude, j'ajouterais les types connus au XmlSerializer dans les méthodes Serial et Deserialize comme ceci :

    string listXml = Serialize<List<A>>(ListA, new Type[] { typeof(B), typeof(C) });

    List<IA> NewList = Deserialize<List<A>>(listXml, new Type[] { typeof(B), typeof(C) });

    private static T Deserialize<T>(string Xml, Type[] KnownTypes)
    {
        XmlSerializer xs = new XmlSerializer(typeof(T),KnownTypes);

        StringReader sr = new StringReader(Xml);
        return (T)xs.Deserialize(sr);
    }

    private static string Serialize<T>(Object obj, Type[] KnownTypes)
    {
        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            XmlSerializer xs = new XmlSerializer(typeof(T), KnownTypes);

            xs.Serialize(sw, obj);
        }
        return sb.ToString();
    }

4voto

Arthur Points 5474

Oui, mais vous devez jouer avec les attributs XmlElement, XmlRoot et XmlArray. Chaque type a besoin de son propre nom d'élément.

EDIT : Quelques exemples de code. Toutes les classes sont dérivées d'une classe de base commune.

Voici un exemple de code :

[XmlRoot(ElementName="Root")]
public sealed class SomeObject
{

    private BaseObject _Object;

    [XmlElement(Type=typeof(App.Projekte.Projekt), ElementName="Projekt")]
    [XmlElement(Type=typeof(App.Projekte.Task), ElementName="Task")]
    [XmlElement(Type=typeof(App.Projekte.Mitarbeiter), ElementName="Mitarbeiter")]
    public BaseObject Object
    {
        get
        {
            return _Object;
        }
        set
        {
            _Object = value;
        }
    }
}

EDIT : Supprimez l'attribut Serialization car il n'est pas nécessaire (mais il est nécessaire dans mon projet d'où provient le code).

4voto

Darin Dimitrov Points 528142

Vous pouvez essayer d'utiliser DataContractSerializer :

public interface A
{
}

public class B : A
{
}

public class C : A
{
}

class Program
{
    static void Main(string[] args)
    {
        List<A> list = new List<A>(new A[] { new B(), new C() });
        var serializer = new DataContractSerializer(
            list.GetType(), new[] { typeof(B), typeof(C) });

        var sb = new StringBuilder();
        using (var stringWriter = new StringWriter(sb))
        using (var writer = XmlWriter.Create(stringWriter))
        {
            serializer.WriteObject(writer, list);
        }

        using (var stringReader = new StringReader(sb.ToString()))
        using (var reader = XmlReader.Create(stringReader))
        {
            list = (List<A>)serializer.ReadObject(reader);
        }

    }
}

0voto

viky Points 5893

Dans votre cas, créez une classe abstraite qui implémente votre interface, par exemple :

abstract class Abs : A

puis dérivez vos classes à partir d'Abs

public class B : Abs
public class C : Abs

et Liste des listes ;

Utilisez maintenant XmlIncludeAttribute pour ajouter vos types dans le tableau de types de XmlSerializer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X