XmlSerializer的构造器将List< T>序列化.与XmlAttributeOverrides一起使用时引发InvalidOperationException [英] Constructor of a XmlSerializer serializing a List<T> throws an InvalidOperationException when used with XmlAttributeOverrides

查看:46
本文介绍了XmlSerializer的构造器将List< T>序列化.与XmlAttributeOverrides一起使用时引发InvalidOperationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要

使用XmlSerializer类时,使用诸如XmlAttributeOverrides这样的序列化List<T>(其中T可以用XmlSerializer进行序列化而没有问题):

When using the XmlSerializer class, serializing a List<T> (where T can be serialized with XmlSerializer without problems) using XmlAttributeOverrides such as this:

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:

will throw the following InvalidOperationExcpetion at the inner-most exception:

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纹理的类.

I have been messing around with XML Serialization lately but have come across a problem. I am trying to serialize and deserialize some classes that wrap OpenGL textures.

在我的一个类中(我恰当地称为BitmapTexture2d),我有一个Bitmap字段,我希望将其存储在Base64元素中,如下所示:

In one of my classes (which I appropriately called BitmapTexture2d) I have a Bitmap field, which I wish to store in a Base64 element like so:

<bitmap64>
    *base64goeshere*
</bitmap64>

因为我想使代码尽可能整洁,所以我决定使用IXmlSerializable接口,而不是创建一个可以来回转换stringBitmap的属性.

Since I want to keep my code as neat as possible I decided to use the IXmlSerializable interface instead of creating a property which can convert a string and a Bitmap back and forth.

此后,我决定使用XmlSerializer类为Texture2d(是BitmapTexture2d的来源)中定义的单个字段生成XML,该字段称为Parameters(这是List<TextureParameter>TextureParameter可通过XmlSerialization类进行序列化).但是,这就是序列化程序默认情况下对List<TextureParameter>:

Later on in the process I decided to use the XmlSerializer class to generate the XML for a single field defined in Texture2d (which BitmapTexture2d is derived from) called Parameters (which is a List<TextureParameter> and TextureParameter is serializable by the XmlSerialization class). However this is how the serializer defaulted to serializing the 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的构造函数以添加/覆盖节点名称等.

After seeing this, I decided to try and change the names of the nodes. After some research (where I landed at stackoverflow multiple times) I discovered the XmlAttributeOverrides class which can be passed to the constructor of XmlSerializer to add/override node names etc.

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

After writing out my code, the constructor for the sub-serializer started throwing an exception as described above. I have tried using an array which threw the same exception. I later though to serialize each element in the list one by one, but came to the conclusion that it was harder than I thought to achieve it that way. I posted this question somewhere else with no answer. And here I am...

推荐答案

您的问题是您试图使用替代来附加 [XmlArrayItem] 转换为类型List<T> .但是,如 docs [XmlArray]不能以这种方式使用:

Your problem is that you are trying to use overrides to attach [XmlArray] and [XmlArrayItem] to the type List<T>. However, as shown in the docs, [XmlArray] cannot be used in this manner:

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

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

Notice there is no AttributeTargets.Class included? That means that [XmlArray] cannot be applied directly to a type and so attempting to do so via XML overrides rightly throws an exception.

但是关于该异常消息为何如此说明

But as to why that exception message states,

System.InvalidOperationException:可能没有为类型System.Collections.Generic.List`1 ...

System.InvalidOperationException: XmlRoot and XmlType attributes may not be specified for the type System.Collections.Generic.List`1...

嗯,那条消息简直是错误的.在XmlSerializer中,它似乎是一个较小的错误.您甚至可以根据需要将其报告给Microsoft.

Er, well, that message is simply wrong. It would appear to be a minor bug in XmlSerializer. You could even report it to Microsoft if you want.

您需要做的是:

  • 覆盖

  • Override the [XmlRoot] attribute of List<T> to specify the desired name, in this case "texparams", AND

覆盖 XmlTypeAttribute.TypeName 作为所需的集合元素名称.在没有[XmlArrayItem(name)]覆盖的情况下,这是控制项目类型为T的集合的元素名称的方法.

Override the [XmlType] attribute of T and set XmlTypeAttribute.TypeName to be the desired collection element name. In the absence of an [XmlArrayItem(name)] override this is what controls the element names of collections whose items are of type T.

因此您的代码应如下所示:

Thus your code should look like:

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);
}

示例小提琴.

请注意,使用XmlAttributeOverrides构造XmlSerializer时,必须缓存序列化程序以供​​以后重用,以避免严重的内存泄漏,原因如下

Note that when constructing an XmlSerializer using XmlAttributeOverrides you must cache the serializer for later reuse to avoid a severe memory leak, for reasons explained here.

这篇关于XmlSerializer的构造器将List&lt; T&gt;序列化.与XmlAttributeOverrides一起使用时引发InvalidOperationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆