【发布时间】:2008-09-20 20:45:39
【问题描述】:
使用 .Net 使用 XmlSerializer 有哪些限制(如果有)? 比如,你能把Image序列化成XML吗?
【问题讨论】:
-
请重新标记。这不是特定于 C# 的问题。改为使用“.net”标记。
标签: .net xml serialization
使用 .Net 使用 XmlSerializer 有哪些限制(如果有)? 比如,你能把Image序列化成XML吗?
【问题讨论】:
标签: .net xml serialization
我通常发现 XmlSerializer 对于任何不仅仅是 DTO 的 POCO 来说都是一个糟糕的选择。如果你需要特定的 XML,你可以走 Xml*Attribute 和/或 IXmlSerializable 路线——但你会得到一个相当混乱的对象。
出于某些目的,它仍然是一个显而易见的选择——即使它有局限性。但是,对于简单地存储和重新加载数据,我发现 BinaryFormatter 是一个更容易的选择,而且陷阱更少。
这里列出了 XmlSerializer 的一些烦恼 - 大多数我都曾在某个时候被咬过,其他的我在 MSDN 找到:
XmlSerializer 对实现 IEnumerable 或 ICollection 的类进行特殊处理。实现 IEnumerable 的类必须实现采用单个参数的公共 Add 方法。 Add 方法的参数必须与从 GetEnumerator 返回的值的 Current 属性返回的类型相同,或者该类型的基数之一。
除了 IEnumerable 之外,实现 ICollection 的类(例如 CollectionBase)必须具有采用整数的公共 Item 索引属性(C# 中的索引器),并且必须具有整数类型的公共 Count 属性。 Add 方法的参数必须与从 Item 属性返回的类型相同,或者是该类型的基数之一。对于实现 ICollection 的类,要序列化的值是从索引的 Item 属性中检索的,而不是通过调用 GetEnumerator。
为了提高性能,XML 序列化基础结构动态生成程序集以序列化和反序列化指定类型。基础结构查找并重用这些程序集。此行为仅在使用以下构造函数时发生:
XmlSerializer.XmlSerializer(类型) XmlSerializer.XmlSerializer(类型,字符串)
如果您使用任何其他构造函数,则会生成同一程序集的多个版本并且永远不会卸载,这会导致内存泄漏和性能下降。
如果满足以下条件,则无法实例化 XmlSerializer 以序列化枚举:枚举类型为 unsigned long(C# 中为 ulong),并且该枚举包含任何值大于 9,223,372,036,854,775,807 的成员。
XmlSerializer 类不再序列化标记为 [Obsolete] 的对象。
您必须有权写入临时目录(由 TEMP 环境变量定义)才能反序列化对象。
【讨论】:
XmlSerializer 有一些缺点。
我(愚蠢地)编写了自己的序列化程序来解决其中的一些问题。不要那样做;这是很多工作,你会在几个月后发现其中的细微错误。在编写自己的序列化程序和格式化程序时,我获得的唯一收获是对对象图序列化所涉及的细节有了更大的了解。
我在 WCF 出来时找到了NetDataContractSerializer。它完成了上面 XmlSerializer 没有做的所有事情。它以与 XmlSerializer 类似的方式驱动序列化。一种是用属性装饰各种属性或字段,以通知序列化程序要序列化什么。我用 NetDataContractSerializer 替换了我编写的自定义序列化程序,并且对结果非常满意。我强烈推荐它。
【讨论】:
另一个问题是调用 XmlSerializer 的构造函数会在运行时编译代码,并会生成一个临时 DLL(在 %temp% 文件夹中),其中包含用于反序列化的代码。
在app.config中加入下面几行就可以看代码了:
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="4"/>
</switches>
</system.diagnostics>
第一次序列化一个类会花费很多时间,并且需要具有编译和写入磁盘权限的代码。
解决这个问题的一种方法是使用 VS 2005+ 附带的 sGen.exe 工具预编译这些 DLL。
【讨论】:
不确定是否有任何限制。但是 .NET 1.1 中的 XmlSerialization 中存在内存泄漏错误,您必须创建一个缓存序列化程序对象才能解决此问题...事实上,我不确定如果此问题已在 .net 2.0 或更高版本中得到解决...
【讨论】:
理论上,您编写的任何类都可以通过 XmlSerializer 提供。但是,它只能访问公共字段,并且需要用正确的属性(例如 XmlAttribute)标记类。即使在基本框架中,也不是所有东西都支持 XmlSerializer。例如 System.Collections.Generic.Dictionary。
【讨论】:
我能想到的一个限制是 XmlSerialization 是可选的;意味着您不想序列化的类的任何属性都必须用 [XmlIgnore] 装饰。与所有属性都可选择加入的 DataContractSerializer 相比,您必须显式声明包含属性。这是一个很好的write-up。
图像或其二进制数组被 XmlSerializer 序列化为 base64 编码文本。
【讨论】:
例如,您不能序列化实现 IDictionary 接口的类。
【讨论】:
对于集合,它们需要一个带有单个参数的 Add 方法。如果您只需要文本格式而不是特定的 xml,则可以尝试 JSON。我已经为 .NET 开发了一个,JsonExSerializer,还有其他可用的 http://www.json.org。
【讨论】: