.NET XML Serialization and inheritance

前端 未结 6 491
别跟我提以往
别跟我提以往 2021-02-04 12:08

I have structure like this:

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List list;
相关标签:
6条回答
  • 2021-02-04 12: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);
            }
    
        }
    }
    
    0 讨论(0)
  • 2021-02-04 12:24

    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();
        }
    
    0 讨论(0)
  • 2021-02-04 12:27

    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

    0 讨论(0)
  • 2021-02-04 12:29

    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.

    0 讨论(0)
  • 2021-02-04 12:33

    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)

    0 讨论(0)
  • 2021-02-04 12:36

    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.

    0 讨论(0)
提交回复
热议问题