【问题标题】:XmlSerializer sets null to property after self-closed tag defined as XmlElementXmlSerializer 在定义为 XmlElement 的自闭合标记后将 null 设置为属性
【发布时间】:2018-06-08 08:39:48
【问题描述】:

想象一下具有如下 XML 结构:

[XmlRoot("Foo")]
public class Foo
{
    [XmlElement("Bar")]
    public Bar Bar { get; set; }
    [XmlElement("SuperImportant")]
    public SuperImportant SuperImportant { get; set; }
}

[XmlRoot("Bar")]
public class Bar
{
    [XmlElement("Baz")]
    public XmlElement Baz { get; set; }
}

[XmlRoot("SuperImportant")]
public class SuperImportant
{
    [XmlElement("MegaImportant")]
    public string MegaImportant { get; set; }
}

由于某种原因,Baz 被定义为XmlElement

现在检查此代码:

var template = @"
<Foo>
  <Bar>
    {0}
  </Bar>
  <SuperImportant>
    <MegaImportant>42</MegaImportant>
  </SuperImportant>
</Foo>";

var selfClosed = new StringReader(String.Format(template, "<Baz/>"));    

var openClosePair = new StringReader(String.Format(template, "<Baz></Baz>"));

XmlSerializer xmlSerializer = new XmlSerializer(typeof(Foo));

var o1 = (Foo)xmlSerializer.Deserialize(selfClosed);
Console.WriteLine(o1.SuperImportant == null); // True, it's not there

var o2 = (Foo)xmlSerializer.Deserialize(openClosePair);
Console.WriteLine(o2.SuperImportant == null); // False, it's there

如您所见,如果在类定义中定义为XmlElement 的某个标记似乎是自封闭的,则其父标记之后的元素是nulled。如何配置XmlSerializer 将自闭标签视为开闭对? SuperImportant在这两种情况下都应该反序列化,但不是前者,这是错误的。

【问题讨论】:

  • 为什么你认为案例一可以,而案例二不行?我希望无论之前的元素是否以任何形式存在,SuperImportant 都应该被序列化。我无法想象为什么它应该在自关闭Baz 之后反序列化,而在拥有&lt;Baz&gt;&lt;/Baz&gt; 时应该反序列化。还是我错过了什么?
  • @HimBromBeere 是的,当然,SuperImportant 这两种情况都应该序列化,但不是,这就是我在这里的原因。

标签: c# xml serialization xmlserializer


【解决方案1】:

您应该像这样用[XmlAnyElement("Baz")] 标记属性Baz

[XmlRoot("Bar")]
public class Bar
{
    [XmlAnyElement("Baz")]
    public XmlElement Baz { get; set; }
}

正如docs中解释的那样,这个属性

指定成员(返回XmlElementXmlNode 对象数组的字段)包含表示任何在被序列化或反序列化的对象中没有对应成员的XML 元素的对象。
...
您还可以将 XmlAnyElementAttribute 应用于返回单个 XmlElement 对象的字段。如果这样做,则必须使用 XmlElement 类的属性和方法以递归方式遍历未知元素。

应用属性后,Baz 属性将正确捕获&lt;Baz/&gt;&lt;Baz&gt;&lt;/Baz&gt; 元素,而不会干扰后续节点的反序列化。 [XmlElement("Baz")] 导致您看到的不一致似乎很奇怪,但由于 [XmlAnyElement("Baz")] 旨在处理这种情况,因此应该改用它。

示例工作 .Net fiddle here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多