摘要
使用XmlSerializer
课程时,使用List<T>
序列化XmlSerializer
(其中T可以XmlAttributeOverrides
无序地序列化),如下所示:
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<T>), new xmls.XmlAttributes()
{
XmlArray = new xmls.XmlArrayAttribute("foobar"),
XmlArrayItems = { new xmls.XmlArrayItemAttribute("foo") },
});
将在最内层的异常处抛出以下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]].
我对序列化程序的期望
<texparams>
<texparam pname="TextureMinFilter" value="9729"/>
<texparam pname="TextureMagFilter" value="9729"/>
</texparams>
目前我能成功获得
<ArrayOfTextureParameter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TextureParameter pname="TextureMinFilter" value="9729" />
<TextureParameter pname="TextureMagFilter" value="9728" />
</ArrayOfTextureParameter>
背景资讯
我最近一直在搞乱XML序列化,但遇到了一个问题。我正在尝试序列化和反序列化一些包装OpenGL纹理的类。
在我的一个类(我恰当地称为BitmapTexture2d
)中,我有一个Bitmap
字段,我希望将其存储在Base64元素中,如下所示:
<bitmap64>
*base64goeshere*
</bitmap64>
由于我希望尽可能保持代码整洁,我决定使用IXmlSerializable
界面而不是创建可以来回转换string
和Bitmap
的属性。
在此过程的后期,我决定使用XmlSerializer
类为Texture2d
(BitmapTexture2d
派生的)Parameters
中定义的单个字段生成XML。 (List<TextureParameter>
和TextureParameter
可由XmlSerialization
类序列化。然而,这就是序列化程序默认序列化List<TextureParameter>
:
<ArrayOfTextureParameter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TextureParameter pname="TextureMinFilter" value="9729" />
<TextureParameter pname="TextureMagFilter" value="9728" />
</ArrayOfTextureParameter>
看到这个之后,我决定尝试更改节点的名称。经过一些研究(我多次登陆stackoverflow),我发现XmlAttributeOverrides
类可以传递给XmlSerializer
的构造函数来添加/覆盖节点名称等。
在写出我的代码之后,子序列化器的构造函数开始抛出异常,如上所述。我尝试使用一个抛出相同异常的数组。我后来虽然逐一序列化列表中的每个元素,但得出的结论是,它比我想象的那样难以实现。我在其他地方发布了这个问题没有答案。我在这里......
答案 0 :(得分:3)
您的问题是,您尝试使用替换将[XmlArray]
和[XmlArrayItem]
附加到类型List<T>
。但是,如docs所示,[XmlArray]
不能以这种方式使用:
[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false)] public class XmlArrayAttribute : Attribute
请注意,不包含AttributeTargets.Class
?这意味着[XmlArray]
无法直接应用于类型,因此尝试通过XML覆盖正确地执行此操作会引发异常。
但至于为什么该异常消息表明,
呃,嗯,那个消息是完全错误的。它似乎是System.InvalidOperationException:可能没有为System.Collections.Generic.List`1 ...
类型指定 XmlRoot 和 XmlType 属性
XmlSerializer
中的一个小错误。如果需要,您甚至可以向Microsoft报告。
您需要做的是:
覆盖List<T>
的{{3}}属性以指定所需的名称,在本例中为“texparams”,AND
覆盖T
的{{3}}属性,并将[XmlRoot]
设置为所需的集合元素名称。如果没有[XmlArrayItem(name)]
覆盖,则控制项目类型为T
的集合的元素名称。
因此,您的代码应如下所示:
static XmlSerializer MakeListSerializer<T>(string rootName, string elementName)
{
xmls.XmlAttributeOverrides attributeOverrides = new xmls.XmlAttributeOverrides();
attributeOverrides.Add(typeof(List<T>), 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<T>), attributeOverrides);
}
示例[XmlType]
。
请注意,使用XmlSerializer
构建XmlAttributeOverrides
时,必须缓存序列化程序以便以后重用,以避免严重的内存泄漏,原因如XmlTypeAttribute.TypeName
所述。