序列化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接口,而不是创建一个可以来回转换stringBitmap的属性。

稍后在这个过程中,我决定使用XmlSerializer类为Texture2d (派生自BitmapTexture2d )中定义的单个字段生成XML,称为Parameters (这是一个ListTextureParameter可以通过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指定XmlRootXmlType属性…

呃,那个消息是完全错误的。 它似乎是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时,必须缓存序列化程序以供​​以后重用,以避免严重的内存泄漏,原因如下所述。