【问题标题】:Constructor of a XmlSerializer serializing a List<T> throws an InvalidOperationException when used with XmlAttributeOverrides与 XmlAttributeOverrides 一起使用时,序列化 List<T> 的 XmlSerializer 的构造函数会引发 InvalidOperationException
【发布时间】:2018-04-17 14:46:43
【问题描述】:

总结

使用XmlSerializer 类时,使用XmlAttributeOverrides 序列化List&lt;T&gt;(其中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<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 接口,而不是创建一个可以来回转换stringBitmap 的属性。

在此过程的后期,我决定使用XmlSerializer 类为Texture2dBitmapTexture2d 派生自)中定义的单个字段生成 XML,该字段称为 ParametersList&lt;TextureParameter&gt;并且TextureParameter 可以被XmlSerialization 类序列化)。然而,这就是序列化程序默认序列化List&lt;TextureParameter&gt; 的方式:

<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 的构造函数以添加/覆盖节点名称等。

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

【问题讨论】:

    标签: c# xml list serialization


    【解决方案1】:

    您的问题是您尝试使用覆盖将[XmlArray][XmlArrayItem] 附加到类型List&lt;T&gt;。但是,如docs所示,[XmlArray]不能这样使用:

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

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

    但至于为什么该异常消息状态,

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

    呃,好吧,那条信息完全是错误的。这似乎是XmlSerializer 中的一个小错误。如果您愿意,您甚至可以向 Microsoft 报告。

    你需要做的是:

    • 覆盖List&lt;T&gt;[XmlRoot] 属性以指定所需的名称,在本例中为“texparams”,并且

    • 覆盖T[XmlType] 属性并将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);
    }
    

    示例fiddle

    请注意,在使用 XmlAttributeOverrides 构造 XmlSerializer 时,您必须缓存序列化程序以供​​以后重用以避免严重的内存泄漏,原因已解释为 here

    【讨论】:

    • 答案肯定是正确的,所以我标记了。我发现它必须完成的方式并不直观,但从编程的角度来看是有意义的。我应该在哪里直接向 Microsoft 或 .Net 基金会报告错误?
    • @utkumaden - 我应该向哪里报告错误 - 老实说,我不再确定了。以前XmlSerializer 的错误可以在connect.microsoft.com/VisualStudio 提交。
    猜你喜欢
    • 2020-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多