utk*_*den 3 c# xml serialization list
概括
使用XmlSerializer该类时,使用以下方法序列化 a List<T>(其中 T 可以XmlSerializer毫无问题地序列化)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") },
});
Run Code Online (Sandbox Code Playgroud)
将在最内部的异常处抛出以下 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]].
Run Code Online (Sandbox Code Playgroud)
我对序列化程序的期望
<texparams>
<texparam pname="TextureMinFilter" value="9729"/>
<texparam pname="TextureMagFilter" value="9729"/>
</texparams>
Run Code Online (Sandbox Code Playgroud)
我现在能成功得到什么
<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>
Run Code Online (Sandbox Code Playgroud)
背景信息
我最近一直在忙于 XML 序列化,但遇到了一个问题。我正在尝试序列化和反序列化一些包装 OpenGL 纹理的类。
在我的一个类(我适当地称之为BitmapTexture2d)中,我有一个Bitmap字段,我希望将其存储在 Base64 元素中,如下所示:
<bitmap64>
*base64goeshere*
</bitmap64>
Run Code Online (Sandbox Code Playgroud)
因为我想让我的代码尽可能整洁,所以我决定使用IXmlSerializable接口而不是创建一个可以来回转换 astring和 a的属性Bitmap。
在此过程的后期,我决定使用XmlSerializer该类为在Texture2d(BitmapTexture2d派生自)中定义的单个字段生成 XML,调用Parameters(它是一个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>
Run Code Online (Sandbox Code Playgroud)
看到这一点后,我决定尝试更改节点的名称。经过一些研究(我多次登陆stackoverflow)我发现了XmlAttributeOverrides可以传递给构造函数的类XmlSerializer以添加/覆盖节点名称等。
写出我的代码后,子序列化器的构造函数开始抛出如上所述的异常。我曾尝试使用抛出相同异常的数组。我后来虽然将列表中的每个元素一个一个地序列化,但得出的结论是,以这种方式实现它比我想象的要难。我在其他地方发布了这个问题,但没有答案。而我在这里...
你的问题是,你正在尝试使用替代来连接[XmlArray]和[XmlArrayItem]对类型List<T>。但是,如文档中所示,[XmlArray]不能以这种方式使用:
Run Code Online (Sandbox Code Playgroud)[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。
你需要做的是:
覆盖 的[XmlRoot]属性List<T>以指定所需的名称,在本例中为“texparams”,并且
覆盖的[XmlType]属性T并设置XmlTypeAttribute.TypeName为所需的集合元素名称。在没有[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);
}
Run Code Online (Sandbox Code Playgroud)
样品小提琴。
请注意,在构造XmlSerializerusing 时,XmlAttributeOverrides您必须缓存序列化程序以供以后重用,以避免严重的内存泄漏,原因在此处解释。