代码之家  ›  专栏  ›  技术社区  ›  Jason Coyne

如何序列化基类型集合并在易于阅读的XML中查看具体类型

  •  4
  • Jason Coyne  · 技术社区  · 15 年前

    我有一个列表,其中填充了各种具体类型的对象,这些对象是BaseType的子类

    我正在使用WCF DataContractSerializer

    <Children>
        <BaseType xmlns:d3p1="http://schemas.datacontract.org/2004/07/Tasks"
                  i:type="d3p1:ConcreteTypeA"></BaseType>
        <BaseType xmlns:d3p1="http://schemas.datacontract.org/2004/07/Tasks"
                  i:type="d3p1:ConcreteTypeB"></BaseType>
    </Children>
    

    有没有办法让它产生

    <Children>
        <ConcreteTypeA/>
        <ConcreteTypeB/>
    </Children>
    

    1 回复  |  直到 15 年前
        1
  •  7
  •   Josh    15 年前

    DataContractSerializer的设计不允许您控制输出。它被设计成快速的、隐式的,并且很容易用属性来定义类。

    您需要的是XmlSerializer。这使您可以更好地控制XML输出。

    请注意,在下面的示例中,我指定了许多可以从属性名中推断出来的内容,只是为了让您感觉可以在属性中重写它们。事实上,我认为如果删除所有属性并应用一些knownTypeAttribute,那么整个类都可以序列化,但我还没有测试它。我不知道这是否能提供您所描述的XML(它将在子元素上方创建一个根元素),但希望这能为您指明正确的方向。

    Attributes That Control XML Serialization

    [XmlRoot(Namespace="")]
    public class MyClass {
    
        [XmlArray("Children")]
        [XmlArrayItem("ConcreteTypeA", typeof(ConcreteTypeA))]
        [XmlArrayItem("ConcreteTypeB", typeof(ConcreteTypeB))]
        public BaseType[] Children {
            get;
            set;
        }
    
    }
    
    public class BaseType {
    }
    
    public class ConcreteTypeA : BaseType {
    }
    
    public class ConcreteTypeB : BaseType {
    }
    

    编辑:我刚刚测试,它产生的东西非常接近你所寻求的。

    void Main()
    {
    
        var mc = new MyClass();
        mc.Children = new BaseType[] {
            new ConcreteTypeA(),
            new ConcreteTypeB(),
            new ConcreteTypeA(),
            new ConcreteTypeB()
        };
    
        var serializer = new XmlSerializer(typeof(MyClass));
    
        using ( var str = new StringWriter() ) {
            serializer.Serialize(str, mc);
            str.ToString().Dump();
        }
    
    }
    

    …产生((从顶部移除)

    <MyClass>
      <Children>
        <ConcreteTypeA />
        <ConcreteTypeB />
        <ConcreteTypeA />
        <ConcreteTypeB />
      </Children>
    </MyClass>