我有一个必须从通用接口继承的对象,并且它有一个来自该接口的列表作为属性。
要序列化它会出现问题,因为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是接口?
答案 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);
}
}
}