【问题标题】:Serialize abstract class with custom node name for each concrete class使用每个具体类的自定义节点名称序列化抽象类
【发布时间】:2014-05-05 19:26:38
【问题描述】:

我有一系列水果对象,其中一些是橙子,一些是苹果。
我想将它们序列化为如下所示的列表:

<Fruits>
    <AppleFruit>
         <IsRotten>true</IsRotten>
         <FellFarFromTree>false</FellFarFromTree>
    </AppleFruit>
    <OrangeFruit>
         <IsRotten>false</IsRotten>
         <NumberOfSegments>6</NumberOfSegments>
    </OrangeFruit>
</Fruits>

所以我正在尝试以下方法:

[Serializable]
[XmlInclude(typeof(Apple))]
[XmlInclude(typeof(Orange))]
public abstract class Fruit {
    public bool IsRotten { get; set; }
}

[Serializable]
[XmlRoot("AppleFruit")]
public class Apple : Fruit {
    public bool FellFarFromTree { get; set; }
}

[Serializable]
[XmlRoot("OrangeFruit")]
public class Orange : Fruit {
    public int NumberOfSegments { get; set; }
}

public class Blender {
    public void XmlBlend(params Fruit[] fruits) {
        using (var writer = new XmlTextWriter(@"c:\test\blended_fruits.xml", Encoding.UTF8)) {
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument();
            writer.WriteStartElement("Fruits");

            var serializer = new XmlSerializer(typeof (Fruit));

            foreach (var fruit in fruits) {
                serializer.Serialize(writer, fruit);
            }

            writer.WriteEndElement();
            writer.WriteEndDocument();
        }
    }

    [Test]
    public void TestIt () {
        var blender = new Blender();
        blender.XmlBlend(
            new Apple() {
                FellFarFromTree = false,
                IsRotten = true
            },
            new Orange() {
                IsRotten = false,
                NumberOfSegments = 6
            });
    }
}

但 XmlRoot 属性似乎完全被忽略了。实际输出如下所示:

<Fruits>
  <Fruit xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Apple">
    <IsRotten>true</IsRotten>
    <FellFarFromTree>false</FellFarFromTree>
  </Fruit>
  <Fruit xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Orange">
    <IsRotten>false</IsRotten>
    <NumberOfSegments>6</NumberOfSegments>
  </Fruit>
</Fruits>

我错过了什么?

【问题讨论】:

  • XmlRoot() for Xml Serilization does not work 的可能重复项(尝试XmlType()
  • XmlType("AppleFruit") 只是将xsi:type 更改为"AppleFruit"
  • 关闭,但没有雪茄。这会产生 w3.org/2001/XMLSchema" xmlns:xsi="w3.org/2001/XMLSchema-instance" xsi:type="AppleFruit"> (注意 xsi:type 属性已更改,但节点名称未更改)
  • @MikeRuhlin - 从该答案(XmlElement(),使用XmlAttributeOverrides)中提出任何其他建议,帮助?
  • 不。 XmlElement() 适用于您希望为列表中的所有元素提供相同节点名称的情况。 XmlAttributeOverrides 的行为与我已有的行为相同。

标签: c# .net xml xml-serialization


【解决方案1】:

用我自己的解决方法回答,但如果有人有更好的答案,我会接受。

我为每个类创建了不同的序列化程序并将它们放入字典中:

public Dictionary<Type, XmlSerializer> ShouldntHaveToDoThis = new Dictionary<Type, XmlSerializer>() {
    {typeof(Apple), new XmlSerializer(typeof(Apple))},
    {typeof(Orange), new XmlSerializer(typeof(Orange))}
};

然后为每个项目获取适当的序列化程序:

        foreach (var fruit in fruits) {
            var serializer = ShouldntHaveToDoThis[fruit.GetType()];
            serializer.Serialize(writer, fruit);
        }

【讨论】:

    【解决方案2】:

    一种方法是为Fruits 创建一个类型,其中包含Fruit 的每种类型的列表,并使用XmlElement 属性来命名项目。

    [XmlRoot("Fruits")]
    public class Fruits
    {
        [XmlElement("AppleFruit")]
        public Apple[] Apples { get; set; }
        [XmlElement("OrangeFruit")]
        public Orange[] Oranges { get; set; }
    }
    [Serializable]
    [XmlInclude(typeof(Apple))]
    [XmlInclude(typeof(Orange))]
    public abstract class Fruit {
        public bool IsRotten { get; set; }
    }
    
    [Serializable]
    public class Apple : Fruit {
        public bool FellFarFromTree { get; set; }
    }
    
    [Serializable]
    public class Orange : Fruit {
        public int NumberOfSegments { get; set; }
    }
    
    
    public void XmlBlend(Fruits fruits) {
        using (var writer = new XmlTextWriter(@"c:\test\blended_fruits.xml", Encoding.UTF8)) {
            writer.Formatting = Formatting.Indented;
    
            var serializer = new XmlSerializer(typeof(Fruits));
            serializer.Serialize(writer, fruits);
        }
    }
    

    产生如下输出:

    <?xml version="1.0" encoding="utf-8"?>
    <Fruits xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <AppleFruit>
        <IsRotten>true</IsRotten>
        <FellFarFromTree>false</FellFarFromTree>
      </AppleFruit>
      <OrangeFruit>
        <IsRotten>false</IsRotten>
        <NumberOfSegments>6</NumberOfSegments>
      </OrangeFruit>
    </Fruits>
    

    必须列出Apple[] Apples 等并不是很漂亮,但我认为这类似于在Fruit 上需要[XmlInclude(typeof(Apple))]

    【讨论】:

      猜你喜欢
      • 2016-01-16
      • 1970-01-01
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 2011-11-13
      • 1970-01-01
      • 2021-06-06
      • 2015-03-12
      相关资源
      最近更新 更多