简体   繁体   English

如何序列化接口列表?

[英]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.对其进行序列化会出现问题,因为 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);
            }
        }
    }
}

How can I serialize a List<T> where T is an interface?如何序列化List<T> ,其中 T 是一个接口?

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.您必须使用IXmlSerializable接口并编写自定义序列化。 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.应该没有那么困难 - 您需要枚举您的列表,获取每个对象的基础类型并为此类型创建一个新的XmlSerializer 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.因此,基于 decPLs 的回答,我创建了一个类来完成这项工作。 T must be an interface and it will work: 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);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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