C# .NET XML序列化和继承

C# .NET XML序列化和继承,c#,inheritance,serialization,xml-serialization,C#,Inheritance,Serialization,Xml Serialization,我有这样的结构: public interface A { public void method(); } public class B : A { } public class C : A { } List<A> list; 公共接口A { 公共无效方法(); } B级:A级 { } 公共C类:A { } 名单; 列表包含类型为B和C的对象。它们也有一些我想保留的字段,我现在可以序列化它,反序列化回来并获得正确的对象实例吗? 最好使用XML 编辑: 有没有简单的方

我有这样的结构:

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;
公共接口A
{
公共无效方法();
}
B级:A级
{
}
公共C类:A
{
}
名单;
列表包含类型为B和C的对象。它们也有一些我想保留的字段,我现在可以序列化它,反序列化回来并获得正确的对象实例吗? 最好使用XML

编辑:


有没有简单的方法可以序列化包含接口的列表,然后将其反序列化回B和C实例?

是的,但必须使用XmlElement、XmlRoot和XmlArray属性。 每种类型都需要自己的元素名

编辑:一些示例代码。所有类都派生自一个公共基类

下面是一个示例代码:

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

编辑:删除Serialization属性,因为它不是必需的(但在我的代码所在的项目中是必需的)

假设您使用的是内置的.net XML序列化,您应该查看以下属性:

System.Xml.Serialization.XmlIncludeAttribute
它允许您指示序列化程序在序列化/反序列化时包含其他类型


向列表中添加新类型和不更新序列化元数据是常见的错误源,请确保您有足够的测试覆盖率。

针对您的情况,创建一个实现接口的抽象类,如:

abstract class Abs : A
然后从Abs派生类

public class B : Abs
public class C : Abs
及 名单


现在使用XmlIncludeAttribute将类型添加到XmlSerializer的类型数组中

我将使用抽象类而不是接口(因为无法序列化接口类型),然后,我将在串行和反序列化方法中将已知类型添加到XmlSerializer中,而不是使用XmlInclude属性对类型进行硬编码,如下所示:

    string listXml = Serialize<List<A>>(ListA, new Type[] { typeof(B), typeof(C) });

    List<IA> NewList = Deserialize<List<A>>(listXml, new Type[] { typeof(B), typeof(C) });

    private static T Deserialize<T>(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<T>(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();
    }
stringlistxml=Serialize(ListA,新类型[]{typeof(B),typeof(C)});
List NewList=反序列化(listXml,新类型[]{typeof(B),typeof(C)});
私有静态T反序列化(字符串Xml,类型[]KnownTypes)
{
XmlSerializer xs=新的XmlSerializer(类型(T),KnownTypes);
StringReader sr=新的StringReader(Xml);
返回(T)xs.反序列化(sr);
}
私有静态字符串序列化(对象对象对象,类型[]KnownTypes)
{
StringBuilder sb=新的StringBuilder();
使用(StringWriter sw=新StringWriter(sb))
{
XmlSerializer xs=新的XmlSerializer(类型(T),KnownTypes);
序列化(sw,obj);
}
使某人返回字符串();
}

XmlSerializer
不能与接口一起工作。因此,您可以:

将接口转换为抽象类,然后对其使用
xmlcludeAttribute
,或向
XmlSerializer

为父类型实现
IXmlSerializable

请考虑使用.NET 3.0中的版本。您可以尝试使用:

公共接口A
{
}
B级:A级
{
}
公共C类:A
{
}
班级计划
{
静态void Main(字符串[]参数)
{
列表=新列表(新A[]{new B(),new C()});
var serializer=新的DataContractSerializer(
list.GetType(),new[]{typeof(B),typeof(C)});
var sb=新的StringBuilder();
使用(var stringWriter=新stringWriter(sb))
使用(var writer=XmlWriter.Create(stringWriter))
{
serializer.WriteObject(writer,list);
}
使用(var stringReader=newstringreader(sb.ToString()))
使用(var reader=XmlReader.Create(stringReader))
{
list=(list)serializer.ReadObject(reader);
}
}
}

您不需要
[可序列化]
。XML序列化不使用它。
public interface A
{
}

public class B : A
{
}

public class C : A
{
}

class Program
{
    static void Main(string[] args)
    {
        List<A> list = new List<A>(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<A>)serializer.ReadObject(reader);
        }

    }
}