.NET XML序列化和inheritance
我有这样的结构:
public interface A { public void method(); } public class B : A { } public class C : A { } List list;
List包含B和C类型的对象,它们还有一些我想保留的字段,我现在可以序列化它,反序列化并获取正确的对象实例吗? 最好是XML
编辑:
是否有任何简单的方法来序列化包含接口的列表,然后将其反序列化回B和C实例?
您可以尝试使用DataContractSerializer :
public interface A { } public class B : A { } public class C : A { } class Program { static void Main(string[] args) { List list = new List(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)serializer.ReadObject(reader); } } }
假设您正在使用内置的.net XML序列化,您应该查看以下属性:
System.Xml.Serialization.XmlIncludeAttribute
它允许您在序列化/反序列化时指示序列化程序包含其他类型。
向列表中添加新类型而不更新序列化元数据是错误的常见原因,请确保您有足够的测试覆盖率。
我会使用抽象类而不是接口(因为不能序列化某种类型的接口),然后使用XmlInclude属性而不是硬编码类型,我会在串行和反序列化方法中将已知类型添加到XmlSerializer中,如此:
string listXml = Serialize>(ListA, new Type[] { typeof(B), typeof(C) }); List NewList = Deserialize>(listXml, new Type[] { typeof(B), typeof(C) }); private static T Deserialize(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 (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(); }
是的,但您必须使用XmlElement,XmlRoot和XmlArray属性。 每个Type都需要它自己的元素名称。
编辑:一些示例代码。 所有类都派生自一个公共基类。
这是一个示例代码:
[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; } } }
编辑:删除序列化属性,因为它不需要(但在我的项目中需要代码来自)
对于您的情况,创建一个实现您的接口的抽象类,如:
abstract class Abs : A
然后从Abs派生你的类
public class B : Abs public class C : Abs
和清单清单;
现在使用XmlIncludeAttribute将您的类型添加到XmlSerializer的类型数组中。
XmlSerializer
不适用于接口。 所以你可以:
将接口转换为抽象类,然后为其使用XmlIncludeAttribute
或将KnownTypes提供给XmlSerializer
要么
为父类型实现IXmlSerializable
要么
考虑使用.NET 3.0中的DataContractSerializer