Pytanie .NET Serializacja i dziedziczenie XML


Mam strukturę taką jak ta:

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;

Lista zawiera obiekty typu B i C, które również mają pewne pola, które chciałbym zachować, czy mogę je teraz serializować, deserializować z powrotem i uzyskać odpowiednie instancje obiektów? Najlepiej do XML

EDYTOWAĆ:

Czy istnieje prosty sposób na serializację tej listy, która zawiera interfejsy, a następnie przekształcenie jej z powrotem na instancje B i C?


11
2017-11-10 15:44


pochodzenie




Odpowiedzi:


Możesz spróbować użyć 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);
        }

    }
}

4
2017-11-11 08:50





Zakładając, że używasz wbudowanej serializacji XML .net, powinieneś rzucić okiem na następujący atrybut:

System.Xml.Serialization.XmlIncludeAttribute

To pozwala polecić serializerowi włączenie innych typów podczas serializowania / deserializacji.

Dodanie nowych typów do listy i brak aktualizacji danych metadanych serializacji jest częstym źródłem pomyłek, upewnij się, że masz odpowiedni zasięg testu.


6
2017-11-10 15:47





Chciałbym użyć klasy abstrakcyjnej zamiast interfejsu (ponieważ nie można serializować typu interfejsu), wtedy zamiast twardego kodowania typu za pomocą atrybutu XmlInclude, dodałbym znane typy do XmlSerializer w metodach Serial i Deserialize, :

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

5
2017-11-10 19:46





Tak, ale musisz grać z atrybutami XmlElement, XmlRoot i XmlArray. Każdy typ wymaga nazwy własnego elementu.

EDYCJA: Niektóre przykładowy kod. Wszystkie klasy pochodzą od wspólnej klasy bazowej.

Oto przykładowy kod:

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

EDYCJA: Usuń atrybut Serializacji, ponieważ nie jest potrzebny (ale jest potrzebny w moim projekcie, z którego pochodzi kod)


4
2017-11-10 15:46



Nie potrzebujesz [Serializable]. Nie jest używany przez szeregowanie XML. - John Saunders


Dla swojego przypadku utwórz klasę abstrakcyjną, która implementuje twój interfejs, jak:

abstract class Abs : A

a następnie wyprowadź swoje klasy z Abs

public class B : Abs
public class C : Abs

i     Lista list;

teraz użyj XmlIncludeAttribute, aby dodać swoje typy do tablicy typów XmlSerializer.


0
2017-11-10 16:47





XmlSerializer nie działa z interfejsami. Więc możesz:

Konwertuj interfejs na klasę abstrakcyjną, a następnie użyj XmlIncludeAttribute dla niego lub podaj znane typy XmlSerializer

lub

Wprowadzić w życie IXmlSerializable dla typu macierzystego

lub

Rozważ użycie DataContractSerializer z .NET 3.0


0
2017-11-11 06:59