使用.Net使用XmlSerializer有什么限制(如果有)?

时间:2020-03-06 14:29:34  来源:igfitidea点击:

使用.Net使用XmlSerializer有什么限制(如果有)?
例如,我们可以将图像序列化为XML吗?

解决方案

不知道是否有任何限制。。但是,.NET 1.1中的XmlSerialization中存在内存泄漏错误,我们不得不创建一个缓存序列化程序对象来解决此问题……实际上,我不确定是否该问题已在.net 2.0或者更高版本中修复...

我能想到的一个限制是XmlSerialization是选择退出的。表示我们不希望序列化的类的任何属性都必须用[XmlIgnore]装饰。与选择加入所有属性的DataContractSerializer相比,我们必须显式声明包含属性。这是一个很好的文章。

XmlSerializer将图像或者其二进制数组序列化为base64编码的文本。

理论上,我们编写的任何类都可以通过XmlSerializer进行馈送。但是,它只能访问公共字段,并且需要使用正确的属性(例如XmlAttribute)标记这些类。即使在基本框架中,也不是所有的东西都支持XmlSerializer。例如System.Collections.Generic.Dictionary <>。

XmlSerializer有一些缺点。

  • 它必须知道所有要序列化的类型。我们不能通过表示串行器不知道的类型的接口来传递它。
  • 它不能做循环引用。
  • 如果在对象图中多次引用,它将多次序列化同一对象。
  • 无法处理私有字段序列化。

我(愚蠢地)编写了自己的序列化程序来解决这些问题。不要那样做这是一项繁重的工作,在接下来的几个月中,我们会发现一些细微的错误。我编写自己的序列化器和格式化程序时获得的唯一一件事是对对象图序列化所涉及的细节有了更深的了解。

WCF发布时,我找到了NetDataContractSerializer。它可以执行XmlSerializer不能执行的所有操作。它以与XmlSerializer相似的方式驱动序列化。一个用属性修饰各种属性或者字段,以通知序列化程序要序列化的内容。我用NetDataContractSerializer替换了我编写的自定义序列化程序,并对结果感到非常满意。我会极力推荐它。

例如,我们不能序列化实现IDictionary接口的类。

对于集合,他们需要有一个采用单个参数的Add方法。如果我们只需要文本格式而不是xml,则可以尝试JSON。我已经为.NET,JsonExSerializer开发了一个,在http://www.json.org上也有其他可用的。

对于任何不仅仅是DTO的POCO,我通常都认为XmlSerializer是一个差的选择。如果我们需要特定的XML,则可以使用Xml * Attribute和/或者IXmlSerializable路由,但是我们留下的对象很整齐。

出于某些目的,即使有其局限性,它仍然是一个显而易见的选择。但是,对于简单地存储和重新加载数据,我发现BinaryFormatter是一个更容易选择,陷阱更少的选择。

这是XmlSerializer带来的一些烦恼的清单,我最讨厌的地方就是我在MSDN上发现的其他一些地方:

  • 需要一个公共的,没有参数的构造函数
  • 仅序列化公共读/写属性和字段
  • 要求知道所有类型
  • 实际上是调用get_ *和set_ *,因此将运行验证等。这可能是好是坏(请考虑一下呼叫的顺序)
  • 将仅序列化符合特定规则的IEnumerable或者ICollection集合
The XmlSerializer gives special treatment to classes that implement IEnumerable or ICollection. A class that implements IEnumerable must implement a public Add method that takes a single parameter. The Add method's parameter must be of the same type as is returned from the Current property on the value returned from GetEnumerator, or one of that type's bases. 
  
  A class that implements ICollection (such as CollectionBase) in addition to IEnumerable must have a public Item indexed property (indexer in C#) that takes an integer, and it must have a public Count property of type integer. The parameter to the Add method must be the same type as is returned from the Item property, or one of that type's bases. For classes that implement ICollection, values to be serialized are retrieved from the indexed Item property, not by calling GetEnumerator.
  • 不序列化IDictionary
  • 使用动态生成的程序集,这些程序集可能无法从应用程序域中卸载。
To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when using the following constructors:
  
  XmlSerializer.XmlSerializer(Type)
  XmlSerializer.XmlSerializer(Type, String)
  
  If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance.
  • 无法序列化ArrayList []或者List <T> []
  • 还有其他奇怪的情况
The XmlSerializer cannot be instantiated to serialize an enumeration if the following conditions are true: The enumeration is of type unsigned long (ulong in C#) and the enumeration contains any member with a value larger than 9,223,372,036,854,775,807.
  
  The XmlSerializer class no longer serializes objects that are marked as [Obsolete].
  
  You must have permission to write to the temporary directory (as defined by the TEMP environment variable) to deserialize an object.
  • 需要阅读.InnerException以获取有关错误的任何有用信息

另一个问题是,调用XmlSerializer的构造函数将在运行时编译代码,并将生成带有代码的临时DLL(在%temp%文件夹中)以进行反序列化。

如果将以下行添加到app.config中,则可以观看代码:

<system.diagnostics>
    <switches>
      <add name="XmlSerialization.Compilation" value="4"/>
    </switches>
  </system.diagnostics>

第一次序列化类时,这会花费很多时间,并且需要具有编译和写入磁盘权限的代码。

解决该问题的一种方法是使用VS 2005+附带的sGen.exe工具对这些DLL进行预编译。

在这里查看更多信息。