XML 标有 [XmlAttribute] 的列表 <int> 上的 Xamarin Android 中的反序列化错误
XML deserialization error in Xamarin Android on List<int> marked with [XmlAttribute]
我在反序列化在 Windows 和 Xamarin Android.
的多平台项目中使用的对象时遇到问题
ConfigProperty
class由程序创建、使用和填充,然后序列化为XML存储。在读取并反序列化 Android 中的 class 后,我得到一个 System.ArgumentNullException: Value cannot be null. Parameter name: elementType
。 Windows 中的反序列化工作完美。
我将问题缩小到 DeviceIdentifierIndices
属性,一个整数列表。当属性不存在时,即列表在序列化时为空,反序列化也有效。真正奇怪的是,当列表被序列化为通常的 XML 元素而不是 XML 属性时,它也适用于两个平台。
现在我正处于可以从属性更改为元素的阶段,但我更愿意将其保留为属性。
有问题的 class 看起来像这样,但其他 classes 也存在问题:
public class ConfigProperty
{
public ushort E2Address { get; set; }
public string NameKey { get; set; }
public string DescriptionKey { get; set; }
public Visibility Visibility { get; set; } // 0: Invisible 1: R 2: RW 3: W
[XmlAttribute]
public List<int> DeviceIdentifierIndices { get; private set; }
...
public ConfigProperty()
{
NameKey = string.Empty;
DescriptionKey = string.Empty;
Visibility = Visibility.ReadWrite;
DeviceIdentifierIndices = new List<int>();
...
}
}
生成的 XML 如下所示:
<ConfigProperty DeviceIdentifierIndices="18 22">
<E2Address>327</E2Address>
<NameKey>lightningInterval</NameKey>
<DescriptionKey>lightningIntervalDescription</DescriptionKey>
<Visibility>2</Visibility>
...
</ConfigProperty>
XML de-/serialization用普通的XmlSerializers
:
public static void Serialize<T>(T data, Stream stream)
{
XmlWriterSettings settings = new XmlWriterSettings
{
CloseOutput = false,
Encoding = Encoding.UTF8,
Indent = true
};
using(XmlWriter tw = XmlWriter.Create(stream, settings))
{
XmlSerializer xs = new XmlSerializer(typeof(T));
xs.Serialize(tw, data);
}
}
public static T Deserialize<T>(Stream stream)
{
using(XmlReader reader = XmlReader.Create(stream))
{
XmlSerializer xs = new XmlSerializer(typeof(T));
return (T)xs.Deserialize(reader);
}
}
...
ConfigProperty config = Export.XmlExport.Deserialize<ConfigProperty>(inputStream);
这是失败的反序列化尝试的堆栈跟踪:
{System.ArgumentNullException: Value cannot be null.
Parameter name: elementType
at System.Array.CreateInstance (System.Type elementType, System.Int32[] lengths) [0x00009] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System/Array.cs:471
at System.Array.CreateInstance (System.Type elementType, System.Int32 length) [0x0000b] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System/Array.cs:451
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListString (System.Xml.Serialization.XmlTypeMapping typeMap, System.String values) [0x00044] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:725
at System.Xml.Serialization.XmlSerializationReaderInterpreter.GetValueFromXmlString (System.String value, System.Xml.Serialization.TypeData typeData, System.Xml.Serialization.XmlTypeMapping typeMap) [0x00009] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:658
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadAttributeMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList) [0x00030] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:255
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList, System.Boolean readBySoapOrder) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:295
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:240
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x000c4] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:230
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x0002e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:193
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObjectElement (System.Xml.Serialization.XmlTypeMapElementInfo elem) [0x00059] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:632
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListElement (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Object list, System.Boolean canCreateInstance) [0x000d7] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:696
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList, System.Boolean readBySoapOrder) [0x00490] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:423
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:240
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x000c4] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:230
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x0002e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:193
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObjectElement (System.Xml.Serialization.XmlTypeMapElementInfo elem) [0x00059] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:632
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListElement (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Object list, System.Boolean canCreateInstance) [0x000d7] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:696
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList, System.Boolean readBySoapOrder) [0x00549] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:435
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:240
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x000c4] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:230
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x0002e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:193
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot (System.Xml.Serialization.XmlTypeMapping rootMap) [0x00056] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:184
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot () [0x00022] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:87
at System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.Serialization.XmlSerializationReader reader) [0x0005e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs:381
at System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.XmlReader xmlReader) [0x00026] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs:358
at Export.XmlExport.Deserialize[T] (System.IO.Stream stream) [0x0002d] in C:\Projekte\xxx\Code\Export\XmlExport.cs:91
at Config.DeviceConfigInfo.FromStream (System.IO.Stream inputStream, Config.DeviceConfigInfoType type) [0x00118] in C:\Projekte\xxx\Code\Config\DeviceConfig.cs:872
at Config.DeviceConfigInfo.FromUri (Android.Content.Context context, Android.Net.Uri uri, System.Boolean decrypt) [0x0001d] in C:\Projekte\xxx\Code\Config\DeviceConfig.cs:816
at xxx.Activities.WorkspaceActivity.OnActivityResult (System.Int32 requestCode, Android.App.Result resultCode, Android.Content.Intent data) [0x00085] in C:\Projekte\xxx\Activities\WorkspaceActivity.cs:249 }
您现有的 class 正在利用 XmlSerializer
的以下模糊记录的功能,即 [XmlAttribute]
可以应用于基元集合,并且集合将被序列化作为一个 XML 属性,其值为 space 分隔的原始值序列。
具体来说,Remarks for XmlAttributeAttribute
状态:
You can assign the XmlAttributeAttribute only to public fields or public properties that return a value (or array of values) that can be mapped to one of the XML Schema definition language (XSD) simple types (including all built-in datatypes derived from the XSD anySimpleType type). The possible types include any that can be mapped to the XSD simple types, including Guid, Char, and enumerations.
但是“值数组”究竟是如何序列化为字符串的呢?如果我按如下方式简化您的模型:
public class ConfigProperty
{
public string NameKey { get; set; }
// Remainder of properties omitted for brevity
[XmlAttribute]
public List<int> DeviceIdentifierIndices { get; private set; }
public ConfigProperty()
{
NameKey = string.Empty;
DeviceIdentifierIndices = new List<int>();
}
}
并使用 xsd.exe
为其生成 XSD,我得到:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ConfigProperty" nillable="true" type="ConfigProperty" />
<xs:complexType name="ConfigProperty">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="NameKey" type="xs:string" />
</xs:sequence>
<xs:attribute name="DeviceIdentifierIndices" use="required">
<xs:simpleType>
<xs:list itemType="xs:int" />
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>
其中 <xs:list>
是 documented by Microsoft to Define a collection of a single simpleType definition and W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes 2.4.1.2 List Datatypes 状态
The ·lexical space· of a ·list· datatype is a set of ·literals· each of which is a space-separated sequence of ·literals· of the ·item type·.
这就是 DeviceIdentifierIndices
在 .Net 上成功序列化为 "18 22"
的原因。
综上所述,这是一个非常晦涩的功能。 Mono 团队很可能从未正确实现或测试过此功能。 (这 similar-sounding Unity forum post 表明其他人也遇到了同样的问题。)因此您可能需要修改 class 以解决该限制。
我没有可用于测试的 Xamarin Android,但用数组替换列表可能会解决问题:
public class ConfigProperty
{
public string NameKey { get; set; }
// Remainder of properties omitted for brevity
[XmlAttribute("DeviceIdentifierIndices")]
public int[] DeviceIdentifierIndicesArray
{
get { return DeviceIdentifierIndices.ToArray(); }
set
{
DeviceIdentifierIndices.Clear();
if (value != null)
DeviceIdentifierIndices.AddRange(value);
}
}
[XmlIgnore]
public List<int> DeviceIdentifierIndices { get; private set; }
public ConfigProperty()
{
NameKey = string.Empty;
DeviceIdentifierIndices = new List<int>();
}
}
事实上,XmlSerializationReaderInterpreter.ReadListString()
seems to assume that listType
is an array type (rather than a generic type like List<int>
) so this might well work for you. (Update: OP writes 的 Mono 源代码:我已经成功地尝试了您的第一个解决方案,因为这对我来说似乎是最干净的,所以这是推荐的解决方案。 )
如果没有,创建代理项字符串 属性 并手动进行解析应该可行:
public class ConfigProperty
{
public string NameKey { get; set; }
// Remainder of properties omitted for brevity
[XmlAttribute("DeviceIdentifierIndices")]
public string XmlDeviceIdentifierIndices
{
get { return String.Join(" ", DeviceIdentifierIndices.Select(i => XmlConvert.ToString(i))); }
set
{
var newList = (value ?? "").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(s => XmlConvert.ToInt32(s)).ToList();
DeviceIdentifierIndices.Clear();
DeviceIdentifierIndices.AddRange(newList);
}
}
[XmlIgnore]
public List<int> DeviceIdentifierIndices { get; private set; }
public ConfigProperty()
{
NameKey = string.Empty;
DeviceIdentifierIndices = new List<int>();
}
}
但是请注意,为第二个解决方法 class 生成的 XSD 将与原始 class 中的 XSD 不同。
将 DeviceIdentifierIndices
序列化为元素而不是属性也会起作用,因为简单类型的集合在序列化为元素时不会序列化为列表数据类型,而是序列化为元素序列,可能带有容器元素,它使用完全不同的代码路径。
演示 fiddle 在三个 class 之间交换 XML 此处:https://dotnetfiddle.net/3PmZHv
我在反序列化在 Windows 和 Xamarin Android.
的多平台项目中使用的对象时遇到问题ConfigProperty
class由程序创建、使用和填充,然后序列化为XML存储。在读取并反序列化 Android 中的 class 后,我得到一个 System.ArgumentNullException: Value cannot be null. Parameter name: elementType
。 Windows 中的反序列化工作完美。
我将问题缩小到 DeviceIdentifierIndices
属性,一个整数列表。当属性不存在时,即列表在序列化时为空,反序列化也有效。真正奇怪的是,当列表被序列化为通常的 XML 元素而不是 XML 属性时,它也适用于两个平台。
现在我正处于可以从属性更改为元素的阶段,但我更愿意将其保留为属性。
有问题的 class 看起来像这样,但其他 classes 也存在问题:
public class ConfigProperty
{
public ushort E2Address { get; set; }
public string NameKey { get; set; }
public string DescriptionKey { get; set; }
public Visibility Visibility { get; set; } // 0: Invisible 1: R 2: RW 3: W
[XmlAttribute]
public List<int> DeviceIdentifierIndices { get; private set; }
...
public ConfigProperty()
{
NameKey = string.Empty;
DescriptionKey = string.Empty;
Visibility = Visibility.ReadWrite;
DeviceIdentifierIndices = new List<int>();
...
}
}
生成的 XML 如下所示:
<ConfigProperty DeviceIdentifierIndices="18 22">
<E2Address>327</E2Address>
<NameKey>lightningInterval</NameKey>
<DescriptionKey>lightningIntervalDescription</DescriptionKey>
<Visibility>2</Visibility>
...
</ConfigProperty>
XML de-/serialization用普通的XmlSerializers
:
public static void Serialize<T>(T data, Stream stream)
{
XmlWriterSettings settings = new XmlWriterSettings
{
CloseOutput = false,
Encoding = Encoding.UTF8,
Indent = true
};
using(XmlWriter tw = XmlWriter.Create(stream, settings))
{
XmlSerializer xs = new XmlSerializer(typeof(T));
xs.Serialize(tw, data);
}
}
public static T Deserialize<T>(Stream stream)
{
using(XmlReader reader = XmlReader.Create(stream))
{
XmlSerializer xs = new XmlSerializer(typeof(T));
return (T)xs.Deserialize(reader);
}
}
...
ConfigProperty config = Export.XmlExport.Deserialize<ConfigProperty>(inputStream);
这是失败的反序列化尝试的堆栈跟踪:
{System.ArgumentNullException: Value cannot be null.
Parameter name: elementType
at System.Array.CreateInstance (System.Type elementType, System.Int32[] lengths) [0x00009] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System/Array.cs:471
at System.Array.CreateInstance (System.Type elementType, System.Int32 length) [0x0000b] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System/Array.cs:451
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListString (System.Xml.Serialization.XmlTypeMapping typeMap, System.String values) [0x00044] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:725
at System.Xml.Serialization.XmlSerializationReaderInterpreter.GetValueFromXmlString (System.String value, System.Xml.Serialization.TypeData typeData, System.Xml.Serialization.XmlTypeMapping typeMap) [0x00009] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:658
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadAttributeMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList) [0x00030] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:255
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList, System.Boolean readBySoapOrder) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:295
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:240
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x000c4] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:230
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x0002e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:193
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObjectElement (System.Xml.Serialization.XmlTypeMapElementInfo elem) [0x00059] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:632
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListElement (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Object list, System.Boolean canCreateInstance) [0x000d7] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:696
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList, System.Boolean readBySoapOrder) [0x00490] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:423
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:240
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x000c4] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:230
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x0002e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:193
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObjectElement (System.Xml.Serialization.XmlTypeMapElementInfo elem) [0x00059] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:632
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListElement (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Object list, System.Boolean canCreateInstance) [0x000d7] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:696
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, System.Boolean isValueList, System.Boolean readBySoapOrder) [0x00549] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:435
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:240
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x000c4] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:230
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Boolean isNullable, System.Boolean checkType) [0x0002e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:193
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot (System.Xml.Serialization.XmlTypeMapping rootMap) [0x00056] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:184
at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot () [0x00022] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs:87
at System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.Serialization.XmlSerializationReader reader) [0x0005e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs:381
at System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.XmlReader xmlReader) [0x00026] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs:358
at Export.XmlExport.Deserialize[T] (System.IO.Stream stream) [0x0002d] in C:\Projekte\xxx\Code\Export\XmlExport.cs:91
at Config.DeviceConfigInfo.FromStream (System.IO.Stream inputStream, Config.DeviceConfigInfoType type) [0x00118] in C:\Projekte\xxx\Code\Config\DeviceConfig.cs:872
at Config.DeviceConfigInfo.FromUri (Android.Content.Context context, Android.Net.Uri uri, System.Boolean decrypt) [0x0001d] in C:\Projekte\xxx\Code\Config\DeviceConfig.cs:816
at xxx.Activities.WorkspaceActivity.OnActivityResult (System.Int32 requestCode, Android.App.Result resultCode, Android.Content.Intent data) [0x00085] in C:\Projekte\xxx\Activities\WorkspaceActivity.cs:249 }
您现有的 class 正在利用 XmlSerializer
的以下模糊记录的功能,即 [XmlAttribute]
可以应用于基元集合,并且集合将被序列化作为一个 XML 属性,其值为 space 分隔的原始值序列。
具体来说,Remarks for XmlAttributeAttribute
状态:
You can assign the XmlAttributeAttribute only to public fields or public properties that return a value (or array of values) that can be mapped to one of the XML Schema definition language (XSD) simple types (including all built-in datatypes derived from the XSD anySimpleType type). The possible types include any that can be mapped to the XSD simple types, including Guid, Char, and enumerations.
但是“值数组”究竟是如何序列化为字符串的呢?如果我按如下方式简化您的模型:
public class ConfigProperty
{
public string NameKey { get; set; }
// Remainder of properties omitted for brevity
[XmlAttribute]
public List<int> DeviceIdentifierIndices { get; private set; }
public ConfigProperty()
{
NameKey = string.Empty;
DeviceIdentifierIndices = new List<int>();
}
}
并使用 xsd.exe
为其生成 XSD,我得到:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="ConfigProperty" nillable="true" type="ConfigProperty" />
<xs:complexType name="ConfigProperty">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="NameKey" type="xs:string" />
</xs:sequence>
<xs:attribute name="DeviceIdentifierIndices" use="required">
<xs:simpleType>
<xs:list itemType="xs:int" />
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>
其中 <xs:list>
是 documented by Microsoft to Define a collection of a single simpleType definition and W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes 2.4.1.2 List Datatypes 状态
The ·lexical space· of a ·list· datatype is a set of ·literals· each of which is a space-separated sequence of ·literals· of the ·item type·.
这就是 DeviceIdentifierIndices
在 .Net 上成功序列化为 "18 22"
的原因。
综上所述,这是一个非常晦涩的功能。 Mono 团队很可能从未正确实现或测试过此功能。 (这 similar-sounding Unity forum post 表明其他人也遇到了同样的问题。)因此您可能需要修改 class 以解决该限制。
我没有可用于测试的 Xamarin Android,但用数组替换列表可能会解决问题:
public class ConfigProperty
{
public string NameKey { get; set; }
// Remainder of properties omitted for brevity
[XmlAttribute("DeviceIdentifierIndices")]
public int[] DeviceIdentifierIndicesArray
{
get { return DeviceIdentifierIndices.ToArray(); }
set
{
DeviceIdentifierIndices.Clear();
if (value != null)
DeviceIdentifierIndices.AddRange(value);
}
}
[XmlIgnore]
public List<int> DeviceIdentifierIndices { get; private set; }
public ConfigProperty()
{
NameKey = string.Empty;
DeviceIdentifierIndices = new List<int>();
}
}
事实上,XmlSerializationReaderInterpreter.ReadListString()
seems to assume that listType
is an array type (rather than a generic type like List<int>
) so this might well work for you. (Update: OP writes
如果没有,创建代理项字符串 属性 并手动进行解析应该可行:
public class ConfigProperty
{
public string NameKey { get; set; }
// Remainder of properties omitted for brevity
[XmlAttribute("DeviceIdentifierIndices")]
public string XmlDeviceIdentifierIndices
{
get { return String.Join(" ", DeviceIdentifierIndices.Select(i => XmlConvert.ToString(i))); }
set
{
var newList = (value ?? "").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(s => XmlConvert.ToInt32(s)).ToList();
DeviceIdentifierIndices.Clear();
DeviceIdentifierIndices.AddRange(newList);
}
}
[XmlIgnore]
public List<int> DeviceIdentifierIndices { get; private set; }
public ConfigProperty()
{
NameKey = string.Empty;
DeviceIdentifierIndices = new List<int>();
}
}
但是请注意,为第二个解决方法 class 生成的 XSD 将与原始 class 中的 XSD 不同。
将 DeviceIdentifierIndices
序列化为元素而不是属性也会起作用,因为简单类型的集合在序列化为元素时不会序列化为列表数据类型,而是序列化为元素序列,可能带有容器元素,它使用完全不同的代码路径。
演示 fiddle 在三个 class 之间交换 XML 此处:https://dotnetfiddle.net/3PmZHv