如何序列化接口列表?

时间:2014-04-11 08:20:32

标签: c# inheritance serialization interface xml-serialization

我有一个必须从通用接口继承的对象,并且它有一个来自该接口的列表作为属性。

要序列化它会出现问题,因为XmlSerialzer无法确定MyClass.Items列表元素中的实际类型。

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

如何序列化List<T>,其中T是接口?

2 个答案:

答案 0 :(得分:1)

不幸的是,它不支持开箱即用,但它可行。您必须使用IXmlSerializable接口并编写自定义序列化。它不应该那么困难 - 您需要通过列表进行枚举,获取每个对象的基础类型并为此类型创建新的XmlSerializer。反序列化可能会有点棘手,因为您需要解析类名以确定运行时类型。

答案 1 :(得分:1)

所以,基于decPLs答案,我创建了一个类来完成这项工作。 T必须是一个界面,它才能正常工作:

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