使用C#abstract class属性进行Xml序列化

时间:2018-04-14 12:25:16

标签: c# xml xml-serialization xmlserializer

我想创建一个通用抽象类型作为我的xml序列化类型的基础:

public abstract class RootElementBase<TEelment>
{
    public IList<TElement> SubElements {get;set;}

    public RootElementBase(){ 
         SubElements = new List<T>(); 
    }
}

我将这样使用:

[XmlRoot(ElementName = "myroot")]
public class MyRoot: RootElementBase<ItemType> {
     [XmlElement("item")] 
     public override List<ItemType> Elements { get; set; }
}

但这不会序列化MyRoot类。实现的类型使用Elements类型的通用抽象类。但是将设置XmlElelemt属性标记。

1 个答案:

答案 0 :(得分:0)

支持派生类型的序列化和反序列化。以下属性控制Xml序列化:

  • [XmlElement]
  • [XmlAttribute]
  • [XmlIgnore]

我们需要指示Xml序列化程序忽略我们希望在具体派生类型中使用的基类成员。

参见 - &gt; https://docs.microsoft.com/en-us/dotnet/standard/serialization/attributes-that-control-xml-serialization

另外,在构造函数中要小心虚拟成员调用 见 - &gt; https://msdn.microsoft.com/en-us/library/ms182331.aspx

试一试:

解决方案1 ​​

使用派生类 MyRoot 作为 XmlSerializer 类型参数

抽象基类:

[Serializable]
public abstract class RootElementBase<TEelment>
{
    [XmlIgnore]
    public virtual List<TEelment> SubElements { get; set; }

    protected RootElementBase()
    {
        SubElements = new List<TEelment>();
    }
}

具体类:

[XmlRoot(ElementName = "myroot")]
public class MyRoot : RootElementBase<ItemType>
{
    [XmlElement("item")]
    public override List<ItemType> SubElements { get; set; }
}

Dummy ItemType类:

public class ItemType
{
    public string Name { get; set; }
}

这将输出以下内容:

<?xml version="1.0"?>
<myroot xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <item>
    <Name>Jim</Name>
  </item>
  <item>
    <Name>Ben</Name>
  </item>
  <item>
    <Name>Tom</Name>
  </item>
</myroot>

测试控制台应用程序:

class Program
{
    static void Main(string[] args)
    {
        MyRoot root = new MyRoot();
        root.SubElements.Add(new ItemType() { Name = "Jim"});
        root.SubElements.Add(new ItemType() { Name = "Ben" });
        root.SubElements.Add(new ItemType() { Name = "Tom" });

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyRoot));
        StringWriter stringWriter = new StringWriter();

        xmlSerializer.Serialize(stringWriter, root);

        Console.WriteLine(stringWriter);

        Console.ReadKey();
    }
}

解决方案2

使用抽象基类 RootElementBase 作为 XmlSerializer 类型参数,并带有XmlRoot覆盖参数

每个MSDN:

  

XML文档的根元素包含所有其他元素。   默认情况下,type参数指定的对象是序列化的   作为根元素。属性,例如XML元素名称   root元素取自type对象。但是,根   参数允许您替换默认对象的信息   指定XmlRootAttribute;该对象允许您设置   不同的命名空间,元素名称等。

https://msdn.microsoft.com/en-us/library/65k4wece(v=vs.110).aspx

抽象基类:

[Serializable]
[XmlInclude(typeof(MyRoot))]
public abstract class RootElementBase<TEelment>
{
    [XmlIgnore]
    public virtual List<TEelment> SubElements { get; set; }

    protected RootElementBase()
    {
        SubElements = new List<TEelment>();
    }
}

具体类:

[XmlRoot(ElementName = "myroot")]
public class MyRoot : RootElementBase<ItemType>
{
    [XmlElement("item")]
    public override List<ItemType> SubElements { get; set; }
}

Dummy ItemType类:

public class ItemType
{
    public string Name { get; set; }
}

使用通用序列化的示例控制台应用

class Program
{
    static void Main(string[] args)
    {
        MyRoot root = new MyRoot();
        root.SubElements.Add(new ItemType() { Name = "Jim"});
        root.SubElements.Add(new ItemType() { Name = "Ben" });
        root.SubElements.Add(new ItemType() { Name = "Tom" });

        string xml = Serialize(root, "myNewRoot");

        Console.WriteLine(xml);

        Console.ReadKey();
    }

    static string Serialize<TElement>(RootElementBase<TElement> tElement, string rootElementName)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(RootElementBase<TElement>),
            new XmlRootAttribute(rootElementName));

        StringWriter stringWriter = new StringWriter();

        xmlSerializer.Serialize(stringWriter, tElement);

        return stringWriter.ToString();
    }
}

注意 - 使用此解决方案,您需要了解动态生成的程序集

动态生成的程序集 为了提高性能,XML序列化基础结构动态生成程序集以序列化和反序列化指定的类型。基础结构查找并重用这些程序集。仅当使用以下构造函数时才会出现此问题:

XmlSerializer.XmlSerializer(Type)

XmlSerializer.XmlSerializer(Type, String)

如果使用任何其他构造函数,则会生成同一程序集的多个版本,并且永远不会卸载,这会导致内存泄漏和性能下降。最简单的解决方案是使用前面提到的两个构造函数之一。否则,您必须将程序集缓存在 Hashtable 中,如以下示例所示。

请参阅MSDN备注:https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer(v=vs.110).aspx