XmlSerializer 在自闭标记定义为 XmlElement 后将 null 设置为 属性

XmlSerializer sets null to property after self-closed tag defined as XmlElement

假设有如下 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

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

您应该将 属性 Baz 标记为 [XmlAnyElement("Baz")],如下所示:

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

docs 中所述,此属性

Specifies that the member (a field that returns an array of XmlElement or XmlNode objects) contains objects that represent any XML element that has no corresponding member in the object being serialized or deserialized.
...
You can also apply the XmlAnyElementAttribute to a field that returns a single XmlElement object. If you do so, you must use the properties and methods of the XmlElement class to recursively iterate through the unknown elements.

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

.Net 工作示例 fiddle here.