与 XmlAttributeOverrides 一起使用时,序列化 List<T> 的 XmlSerializer 的构造函数会引发 InvalidOperationException

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该类为在Texture2dBitmapTexture2d派生自)中定义的单个字段生成 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以添加/覆盖节点名称等。

写出我的代码后,子序列化器的构造函数开始抛出如上所述的异常。我曾尝试使用抛出相同异常的数组。我后来虽然将列表中的每个元素一个一个地序列化,但得出的结论是,以这种方式实现它比我想象的要难。我在其他地方发布了这个问题,但没有答案。而我在这里...

dbc*_*dbc 5

你的问题是,你正在尝试使用替代来连接[XmlArray][XmlArrayItem]类型List<T>。但是,如文档中所示,[XmlArray]不能以这种方式使用:

[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field 
                        | AttributeTargets.Parameter | AttributeTargets.ReturnValue, 
    AllowMultiple = false)]
public class XmlArrayAttribute : Attribute
Run Code Online (Sandbox Code Playgroud)

注意没有AttributeTargets.Class包括在内?这意味着[XmlArray] 不能直接应用于类型,因此尝试通过 XML 覆盖正确地抛出异常。

但至于为什么该异常消息指出,

System.InvalidOperationException:不能为 System.Collections.Generic.List`1 类型指定XmlRootXmlType属性...

呃,嗯,那个消息是完全错误的。这似乎是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您必须缓存序列化程序以供​​以后重用,以避免严重的内存泄漏,原因在此处解释。