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,但它是关于枚举的,我不知道如何使用 int
s 的答案。
如何在不实施 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();
}
}
}
考虑这样一个元素:
<?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,但它是关于枚举的,我不知道如何使用 int
s 的答案。
如何在不实施 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();
}
}
}