【问题标题】:Using C# abstract class property for Xml serialize使用 C# 抽象类属性进行 Xml 序列化
【发布时间】:2018-04-14 12:25:15
【问题描述】:

我想创建一个通用抽象类型作为我的 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 属性标签。

【问题讨论】:

    标签: c# xml xml-serialization xmlserializer


    【解决方案1】:

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

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

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

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

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

    试一试:

    解决方案 1

    使用派生类 MyRoot 作为 XmlSerializer

    type 参数

    抽象基类:

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

    虚拟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 作为带有XmlRoot 覆盖参数的 XmlSerializertype 参数

    每个 MSDN:

    XML 文档的根元素包含所有其他元素。 默认情况下,type参数指定的对象是序列化的 作为根元素。属性,例如 XML 元素名称 根元素取自类型对象。然而,根 参数允许您将默认对象的信息替换为 指定 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; }
    }
    

    虚拟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

    【讨论】:

    • 你能提供错误/堆栈跟踪和示例代码吗?我可以毫无问题地运行上面的代码。
    • @barteloma 我已将示例控制台应用程序添加到我的解决方案中。请参见上文。
    • @barteloma 我添加了第二个替代解决方案,它使用抽象基类 RootElementBase 作为 XmlSerializer 的类型参数和 XmlRoot 覆盖参数。请参阅上面的解决方案 #2。
    猜你喜欢
    • 2016-01-04
    • 2016-07-07
    • 2011-10-07
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多