XmlSerializer的构造器将List< T>序列化.与XmlAttributeOverrides一起使用时引发InvalidOperationException [英] Constructor of a XmlSerializer serializing a List<T> throws an InvalidOperationException when used with XmlAttributeOverrides
问题描述
摘要
使用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
接口,而不是创建一个可以来回转换string
和Bitmap
的属性.
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 ofList<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< T>序列化.与XmlAttributeOverrides一起使用时引发InvalidOperationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!