简体   繁体   中英

How to serialize a list of an interface?

I got an object that has to inherit from a general interface as well as it has a list from that interface as property.

Going to serialize it follows by problems, as the XmlSerialzer is not able to determine the real types that are inside of my MyClass.Items list elements.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace MyTest
{
    public interface IMyInterface
    {
        string TestProperty { get; set; }
    }
    public class MyClass : IMyInterface
    {
        public string TestProperty { get; set; }
        public List<IMyInterface> Items { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            MyClass obj = new MyClass() { TestProperty = "Test" };
            XmlSerializer xs = new XmlSerializer(typeof(MyClass)); // <- throws System.NotSupportedException
            using (XmlWriter xw = XmlWriter.Create("file.xml", new XmlWriterSettings()
            {
                Encoding = Encoding.UTF8,
                Indent = true,
                NewLineHandling = NewLineHandling.Entitize
            }))
            {
                xs.Serialize(xw, obj);
            }
        }
    }
}

How can I serialize a List<T> where T is an interface?

Unfortunately it's not supported out of the box, but it's doable. You would have to use the IXmlSerializable interface and write your custom serialization. It shouldn't be that much difficult - you'd need to enumerate through your list, get the underlying type of each object and create a new XmlSerializer for this type. Deserialization could be a bit more tricky, as you'd need to parse the class names to determine runtime types.

So, based on decPLs answer I've created a class to do this job. T must be an interface and it will work:

public class InterfaceCollection<T> : Collection<T>, IXmlSerializable where T : class
{
    private string Namespace { get; set; }
    private string Assembly { get; set; }

    public InterfaceCollection()
    {
    }

    public InterfaceCollection(IList<T> list, string namespaceOfInheritedTypes = null, string assemblyOfInheritedTypes = null)
        : base(list)
    {
        this.Namespace = namespaceOfInheritedTypes ?? null;
        this.Assembly = assemblyOfInheritedTypes ?? null;
    }

    public InterfaceCollection(string namespaceOfInheritedTypes, string assemblyOfInheritedTypes = null)
    {
        this.Namespace = namespaceOfInheritedTypes ?? null;
        this.Assembly = assemblyOfInheritedTypes ?? null;
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        this.Namespace = reader.GetAttribute("fromNamespace");
        this.Assembly = reader.GetAttribute("fromAssembly");

        reader.MoveToContent();
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                Type type;
                if (this.Assembly != null)
                {
                    type = Type.GetType(this.Namespace + "." + reader.Name + ", " + this.Assembly);
                }
                else
                {
                    type = Type.GetType(this.Namespace + "." + reader.Name);
                }
                if (type != null)
                {
                    XmlSerializer xs = XmlSerializer.FromTypes(new[] { type })[0];
                    this.Items.Add((T)xs.Deserialize(reader));
                }
            }
        }
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("fromNamespace", this.Namespace);
        if (this.Assembly != null) writer.WriteAttributeString("fromAssembly", this.Assembly);
        foreach (T element in this)
        {
            Type type = element.GetType();
            XmlSerializer xs = XmlSerializer.FromTypes(new[] { type })[0];
            xs.Serialize(writer, element);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM