XmlSerializer 序列化属性中的空整数列表

XmlSerializer serializing an empty list of ints in an attribute

考虑这样一个元素:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="XMLSchema1" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Foo">
    <xs:complexType>
      <xs:attribute name="MyList">
        <xs:simpleType>
          <xs:list itemType="xs:int" />
        </xs:simpleType>
      </xs:attribute>
    </xs:complexType>
  </xs:element>
</xs:schema>

例如:

<Foo MyList='1 2 3' />

对应这个C#class:

[Serializable]
public class Foo
{
  [XmlAttribute]
  public int[] MyList { get; set; }
}

这就是(基本上)xsd.exe /classes 生成的内容。

序列化和反序列化效果很好,除了反序列化一个空列表:

var ser = new XmlSerializer(typeof(Foo));
ser.Deserialize(new StringReader("<Foo MyList='' />"));

AFAIK,这是完全合法的 XML,但是 XmlSerializer 会抛出 InvalidOperationException:

System.InvalidOperationException: There is an error in XML document (1, 6). ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderFoo.Read2_Foo(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderFoo.Read3_Foo()
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
   at Blah.Program.Main(String[] args) in Program.cs:line 17

(此异常来自 .NET 4.7.2;.NET Core 2.2 抛出具有几乎相同堆栈跟踪的相同异常。)该异常是有道理的,因为 "" 不是整数。

有这个 similar question,但它是关于枚举的,我不知道如何使用 ints 的答案。

如何在不实施 IXmlSerializable 的情况下对空列表进行反序列化(这涉及大量额外编码)?

我不确定您可以使用序列化程序属性做任何魔术来使它起作用,并且由于它是一个属性,您不能添加复杂类型来帮助隐藏问题。您可以使用将输入作为字符串处理的代理 属性 来解决该问题,虽然它并不漂亮,但避免了对完整的 IXmlSerializable 实现的需要。

[Serializable]
public class Foo
{
    [XmlIgnore]
    public int[] MyList { get; set; }

    [XmlAttribute(AttributeName = "MyList")]
    public string MyListProxy
    {
        get
        {
            if (MyList == null) return String.Empty;
            return String.Join(" ", MyList);
        }
        set
        {
            MyList = String.IsNullOrWhiteSpace(value) ? new int[0] : value
                .Split(' ')
                .Select(a => int.Parse(a))
                .ToArray();
        }
    }
}