序列化List 的XmlSerializer的构造函数在与XmlAttributeOverrides一起使用时会抛出InvalidOperationException
摘要
使用XmlSerializer
类时,使用XmlAttributeOverrides
序列化List
(其中T可以使用XmlSerializer
序列化而没有问题),例如:
using xmls = System.Xml.Serialization; ... xmls.XmlAttributeOverrides attributeOverrides = new xmls.XmlAttributeOverrides(); attributeOverrides.Add(typeof(T), new xmls.XmlAttributes() { XmlRoot = new xmls.XmlRootAttribute("foo") }); attributeOverrides.Add(typeof(List), new xmls.XmlAttributes() { XmlArray = new xmls.XmlArrayAttribute("foobar"), XmlArrayItems = { new xmls.XmlArrayItemAttribute("foo") }, });
将在最内层的exception处抛出以下InvalidOperationExcpetion:
System.InvalidOperationException: XmlRoot and XmlType attributes may not be specified for the type System.Collections.Generic.List`1[[T, programname, Version=versionnumber, Culture=neutral, PublicKeyToken=null]].
我对序列化器的期望
我现在可以成功获得什么
背景资料
我最近一直在搞乱XML Serialization,但遇到了一个问题。 我试图序列化和反序列化一些包装OpenGL纹理的类。
在我的一个类(我恰当地称为BitmapTexture2d
)中,我有一个Bitmap
字段,我希望将其存储在Base64元素中,如下所示:
*base64goeshere*
因为我想尽可能保持我的代码整洁,所以我决定使用IXmlSerializable
接口,而不是创建一个可以来回转换string
和Bitmap
的属性。
稍后在这个过程中,我决定使用XmlSerializer
类为Texture2d
(派生自BitmapTexture2d
)中定义的单个字段生成XML,称为Parameters
(这是一个List
, TextureParameter
可以通过XmlSerialization
类序列化)。 但是,这是序列化程序默认序列化List
:
看到这个后,我决定尝试更改节点的名称。 经过一些研究(我多次登陆stackoverflow),我发现了XmlAttributeOverrides
类,它可以传递给XmlSerializer
的构造函数来添加/覆盖节点名称等。
在写出我的代码之后,子序列化器的构造函数开始抛出exception,如上所述。 我尝试使用一个抛出相同exception的数组。 我后来虽然逐一序列化列表中的每个元素,但得出的结论是,它比我想象的那样难以实现。 我在其他地方发布了这个问题而没有答案。 我在这里……
您的问题是您尝试使用覆盖将[XmlArray]
和[XmlArrayItem]
附加到List
类型 。 但是,如文档中所示, [XmlArray]
不能以这种方式使用:
[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false)] public class XmlArrayAttribute : Attribute
请注意,没有包含AttributeTargets.Class
? 这意味着[XmlArray]
无法直接应用于某个类型 ,因此尝试通过XML覆盖正确地执行此操作会引发exception。
但至于为什么该exception消息表明,
System.InvalidOperationException:可能未为类型System.Collections.Generic.List`1指定XmlRoot和XmlType属性…
呃,那个消息是完全错误的。 它似乎是XmlSerializer
一个小错误。 如果需要,您甚至可以向Microsoft报告。
你需要做的是:
-
覆盖
List
的[XmlRoot]
属性以指定所需的名称,在本例中为“texparams”,AND -
覆盖
T
的[XmlType]
属性,并将XmlTypeAttribute.TypeName
设置为所需的集合元素名称。 在没有[XmlArrayItem(name)]
覆盖的情况下,这将控制其项目类型为T
的集合的元素名称。
因此,您的代码应如下所示:
static XmlSerializer MakeListSerializer(string rootName, string elementName) { xmls.XmlAttributeOverrides attributeOverrides = new xmls.XmlAttributeOverrides(); attributeOverrides.Add(typeof(List ), new xmls.XmlAttributes() { XmlRoot = new xmls.XmlRootAttribute(rootName), }); attributeOverrides.Add(typeof(T), new xmls.XmlAttributes() { XmlType = new xmls.XmlTypeAttribute(elementName), }); return new XmlSerializer(typeof(List ), attributeOverrides); }
样品小提琴 。
请注意,在使用XmlAttributeOverrides
构造XmlSerializer
时,必须缓存序列化程序以供以后重用,以避免严重的内存泄漏,原因如下所述。