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

Using C# abstract class property for Xml serialize

我想创建一个通用抽象类型作为我的 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 class。已实现的类型对 Elements 类型使用通用抽象 class。但是 XmlElelemt 属性标签会被设置。

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

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

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

查看 -> https://docs.microsoft.com/en-us/dotnet/standard/serialization/attributes-that-control-xml-serialization

此外,请注意构造函数中的虚拟成员调用
请参阅 -> https://msdn.microsoft.com/en-us/library/ms182331.aspx

试一试:

解决方案 1

使用派生的 class MyRoot 作为 type 参数用于 Xml序列化器

抽象基础class:

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

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

具体Class:

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

虚拟物品类型Class:

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

使用抽象基础 class RootElementBase 作为 type 参数 XmlSerializer 带有 XmlRoot 覆盖参数

根据 MSDN:

The root element of an XML document encloses all the other elements. By default, the object specified by the type parameter is serialized as the root element. Properties, such as the XML element name of the root element are taken from the type object. However, the root parameter allows you to replace the default object's information by specifying an XmlRootAttribute; the object allows you to set a different namespace, element name, and so on.

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

抽象基础 Class:

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

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

具体Class:

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

虚拟物品类型Class:

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