.NET XML序列化和继承

11
我有这样的结构:
public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;

我有一个包含B和C类型对象的列表,其中它们还具有一些字段,我想要保留它们,现在我能够对其进行序列化,反序列化并获取正确的对象实例吗?最好是序列化为XML格式。

编辑:

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

6个回答

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

System.Xml.Serialization.XmlIncludeAttribute

它允许您指示序列化程序在序列化/反序列化时包含其他类型。

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


5

我建议使用抽象类而不是接口(因为接口类型无法进行序列化),然后在XmlSerializer的Serial和Deserialize方法中添加已知类型,而不是使用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();
    }

4

是的,但你需要使用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;
        }
    }
}

编辑:删除序列化属性,因为它不是必需的(但在我的项目中需要,因为代码来自该项目)


1
你不需要 [Serializable]。XML 序列化不使用它。 - John Saunders

4

您可以尝试使用DataContractSerializer

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

    }
}

0
为您的情况创建一个实现接口的抽象类,如下所示:

abstract class Abs : A

然后从Abs派生你的类

public class B : Abs
public class C : Abs

并且 List列表;

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


0

XmlSerializer 不支持接口。因此,您可以:

将接口转换为抽象类,然后使用 XmlIncludeAttribute 或提供 KnownTypes 给 XmlSerializer

或者

为父类型实现 IXmlSerializable

或者

考虑使用 .NET 3.0 中的 DataContractSerializer


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接