.NET XML Serialization and inheritance

2019-03-13 01:23发布

I have structure like this:

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;

List contains objects of type B and C they also have some fields that I would like to keep, can I now serialize it, deserialize back and get the proper object instances? Preferably to XML

EDIT:

Is there any simple way to serialize this list that contains interfaces, and then deserialize it back to B and C instances?

6条回答
Evening l夕情丶
2楼-- · 2019-03-13 02:00

I would use an abstract class instead of an interface (as one cannot serialize a type of interface), then instead of hard coding the type using the XmlInclude attribute, I would add the known types to the XmlSerializer in the Serial and Deserialize methods like so:

    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();
    }
查看更多
叛逆
3楼-- · 2019-03-13 02:08

For your case make an abstract class that implements your interface like:

abstract class Abs : A

and then derive your classes from Abs

public class B : Abs
public class C : Abs

and List list;

now use XmlIncludeAttribute to add your types into the XmlSerializer's type array.

查看更多
forever°为你锁心
4楼-- · 2019-03-13 02:12

XmlSerializer does not work with interfaces. So you can:

Convert interface to abstract class and then use XmlIncludeAttribute for it or provide KnownTypes to XmlSerializer

or

Implement IXmlSerializable for the parent type

or

Consider using DataContractSerializer from .NET 3.0

查看更多
对你真心纯属浪费
5楼-- · 2019-03-13 02:14

You may try using 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);
        }

    }
}
查看更多
可以哭但决不认输i
6楼-- · 2019-03-13 02:21

Yes, but you have to play with the XmlElement, XmlRoot and XmlArray Attributes. Each Type needs it's own element name.

EDIT: Some sample code. All classes are derived from a common base class.

Here is a sample 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: Remove Serialization Attribute as it's not needed (but is needed in my project where the code is from)

查看更多
一纸荒年 Trace。
7楼-- · 2019-03-13 02:26

Assuming you're using the built in .net XML serialization you should take a look at the following attribute:

System.Xml.Serialization.XmlIncludeAttribute

It allows you to instruct the serializer to include other types when serializing/deserializing.

Adding new types to the list and not updating the serialization meta data is a common source of mistakes, make sure you have adequate test coverage.

查看更多
登录 后发表回答