如何在.NET中使用可扩展的对象层次结构正确地XML序列化集合?

时间:2012-01-22 22:01:54

标签: .net oop xml-serialization

情景:

  1. 我有4个课程,ConfigurationOptionOption1Option2
  2. Option1Option2继承自Option
  3. Configuration有一个List<Option>类型的属性,我打算在其中存储从Option下载的对象
  4. Option是抽象的,永远不会用于构造实际的实例。
  5. 问题:

    • 当我简单地用简单的[XmlType(...)][XmlElement(...)]属性注释这些对象和成员时,集合中对象的序列化最终会与我想要的不同
    • 如果我添加了必要的[XmlArray(...)][XmlArrayItem(...)]属性,它看起来像我想要的那样,但是我必须在编译时指定一个已知的项类型列表,这样就无法实现可扩展性

    以下是您可以运行的示例LINQPad脚本:

    void Main()
    {
    
        var Configuration = new Configuration();
        Configuration.Options.Add(new Option1());
        Configuration.Options.Add(new Option2());
    
        var serializer = new XmlSerializer(typeof(Configuration), new Type[]
        {
            typeof(Option1),
            typeof(Option2),
        });
        var ns = new XmlSerializerNamespaces();
        ns.Add(string.Empty, string.Empty);
    
        using (var writer = new StringWriter())
        {
            serializer.Serialize(writer, Configuration, ns);
            writer.ToString().Dump();
        }
    }
    
    [XmlType("configuration")]
    public class Configuration
    {
        private readonly List<Option> _Options = new List<Option>();
    
        [XmlElement("options")]
        public List<Option> Options { get { return _Options; } }
    
        [XmlArray("options2")]
        [XmlArrayItem(typeof(Option1))]
        [XmlArrayItem(typeof(Option2))]
        public List<Option> Options2 { get { return _Options; } }
    }
    
    public class Option { }
    
    [XmlType("option1")]
    public class Option1 : Option { }
    
    [XmlType("option2")]
    public class Option2 : Option { }
    

    运行此命令时,您将获得以下输出:

    <?xml version="1.0" encoding="utf-16"?>
    <configuration>
      <options d2p1:type="option1" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance" />
      <options d2p1:type="option2" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance" />
      <options2>
        <option1 />
        <option2 />
      </options2>
    </configuration>
    

    请注意第一个属性options的序列化与options2完全不同,但它们具有相同的内容。

    基本上,我希望序列化的xml看起来像options2,但不必通过属性指定允许的类类型,因为这将使扩展性变得不可能。

    如果我必须通过可在运行时更改的内容提供它们,那很好,但在编译时硬编码是不行的。

1 个答案:

答案 0 :(得分:2)

我认为您将不得不查看XmlAttributeOverrides,它允许您在运行时提供属性。这不是琐碎的,但也不是精神融化。最大的问题:当你使用接受XmlAttributeOverrides的构造函数时,每次都会生成 ,所以一定要缓存并重新使用XmlSerializer实例 - 否则你会泄漏组件(它们无法收集)。

要实施,您需要调整XmlAttributesXmlArray的{​​{1}}实例,然后使用XmlArrayItems将其与XmlAttributeOverrides.Add(Type,Member,XmlAttributes)相关联。