有没有不使用XmlSerializer的理由?

11
我刚学习了 .Net 中的 XmlSerializer 类。以前我一直使用标准类来解析和编写我的 XML。在深入研究之前,我想知道是否存在不适用该选项的情况。
编辑:所说的标准类指的是 XmlDocument、XmlElement、XmlAttribute 等类。

3
“标准课程”是指哪些课程?这个问题需要澄清。 - Dan Davies Brackett
1
@DDavies:我相信他指的是使用XmlDocument、XmlElement、XmlAttribute等W3C标准兼容的XML类。 - jrista
8个回答

13

当您使用XmlSerializer时,会有许多限制:

  • 必须拥有一个无参构造函数(正如评论中所提到的,它不一定是公共的)
  • 只能序列化公共属性
  • 接口类型无法序列化
  • 还有一些其他限制...

这些限制经常迫使您做出某些设计决策,这些决策并不是在其他情况下您会做出的决策...而且,强制您做出糟糕的设计决策的工具通常不是一个好东西 ;)

话虽如此,当您需要快速将简单对象存储为XML格式时,它可以非常方便。我也喜欢它可以对生成的模式进行相当好的控制。


请注意,无参数构造函数不一定需要是公共的。private 和 internal 也可以使用。 - idlewire
@idlewire,你说得对,我以前从未意识到这一点。但是我怀疑只有在完全信任的情况下才能运行。 - Thomas Levesque
反序列化将执行设置访问器,您可能不希望发生这种情况。反序列化将访问无参数构造函数,您可能不希望发生这种情况。您编写代码是为了实现业务目的,不一定希望XmlSerializer使用相同的代码来实现其目的。其中一种替代方案DataContractSerializer也会运行set访问器,但至少它不需要一个无参数构造函数。您可以通过使用[DataMember]装饰私有备份存储而不是装饰属性来避免任何setter副作用。 - H2ONaCl

5

显然,它并不能给你完全控制输出。个人认为,LINQ to XML足以让我轻松手写这个过程,对于相对较小的项目,我很乐意用这种方式完成它。如果你正在使用.NET 3.5或4,但没有使用LINQ to XML,请立即尝试一下——它比旧的DOM好得多。

有时候,能够控制序列化和反序列化是很好的......特别是当你改变数据布局的时候。如果你不处于这种情况中,并且不预计会遇到这种情况,那么内置的XML序列化可能就可以胜任了。

编辑:我不认为XML序列化支持构建真正的不可变类型,而手工构建则显然是可行的。作为一个不可变性的粉丝,这肯定是我关注的问题之一。如果你实现了IXmlSerializable接口,我相信你可以做到public不可变性,但你仍然必须是私有可变的。当然,我可能是错的——但这值得检查。


你能否稍微澄清一下,当你说你是不可变性的粉丝时,你的意思是什么?你处理XML序列化的一般策略是什么? - Dmitrii Lobanov
2
@Dmitry:我发现当我的类型是不可变的时候,代码更容易理解,并且多线程编程更简单。对于 XML 序列化,我经常需要手动编写自己的 ToXElement 和 FromXElement 代码。这很少有困难,并且最终你拥有完全控制生成的内容。 - Jon Skeet

5
XmlSerializer可以帮助您避免在定期序列化和反序列化相同类型时遇到的大量问题,如果您需要这些类型的序列化表示形式可供不同平台(例如Java、Javascript等)使用。我建议在可以使用XmlSerializer时尽量使用它,因为它可以减轻您自己管理从对象图到XML转换时的大量麻烦。
但也有一些情况并不适合使用XmlSerializer,以下是其中一些情况:
- 当您需要快速处理大量xml数据时,请使用XmlReader。 - 当您需要使用XPath在xml文档中执行重复搜索时。 - 当xml文档结构相当任意,并且不经常符合已知对象模型时。 - 当XmlSerializer强加了不满足您设计要求的要求时:
- 不能使用默认公共构造函数时,请勿使用它。 - 您无法使用xml序列化器属性来定义元素和属性名称的xml变体,以符合必要的Xml模式。

+1 对于提到 size-argument 和 XmlReader 作为替代方法。 - Abel

4

我认为XmlSerializer的主要缺点有:

1)对于涉及集合的复杂对象图,有时使用序列化控制属性很难获得您想要的XML模式。

2)如果在应用程序的一个版本和下一个版本之间更改类定义,则文件将变得无法读取。


4
#2 是我发现许多程序员害怕的大问题。 - Neil N
1
它仍然不像BinarySerializer那样脆弱。 - Callum Rogers

2

是的,我个人使用自动XML序列化 - 尽管最初使用DataContractSerializer是因为WCF(即使没有任何属性也能够序列化类型非常有帮助),因为它不会嵌入类型。当然,因此在加载时需要知道您正在反序列化的对象类型。

这其中的大问题是,如果不实现IXmlSerializable,很难将其序列化为属性,或者暴露一些其他类型,以便序列化程序可以本地处理。

我想最大的陷阱是您无法自动序列化接口,因为DCS希望在接收到XML后能够重新构造实例。但是,标准集合接口是本地支持的。

总的来说,我发现DCS路线是最快且最无痛的方式。

作为替代方案,您还可以使用Linq to XML读取和写入XML,如果您想要完全控制 - 但是您仍然必须逐个成员地处理类型。

最近我一直在研究它(之前一直避免它,因为我看不出意义),在阅读Jon Skeet新书的早期版本后,我必须说 - 我对它如何轻松处理XML印象深刻。


1

我过去经常使用XmlSerializer,将来可能也会继续使用。然而,最大的陷阱已经在上面提到:

序列化器的限制(如限制为公共成员)要么1)对类施加与其主要功能无关的设计约束,要么2)强制增加解决这些约束的复杂性。

当然,其他方法的Xml序列化也会增加复杂性。

所以我想我的答案是,并没有适用于所有情况的正确或错误答案;选择序列化方法只是众多设计考虑之一。


0

有一些情况需要考虑。

  • 你必须处理大量的XML数据 - 序列化器可能会超载你的内存。我曾经为一个简单的模式处理了包含2000个左右表格的数据库转储,只用了几个类,但最终序列化并没有起作用 - 我不得不使用SAX流解析器。

除此之外 - 在正常情况下我没有看到任何问题。与使用更低级别的解析器相比,使用XML序列化器处理更复杂的数据是更容易的方法。


-1

当您想要传输大量数据且资源非常有限时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接