XmlSerializer和BinaryFormatter之间有什么区别?

51
上周我花了很多时间在序列化方面的工作上。在这段时间里,我发现了许多使用BinaryFormatter或XmlSerializer的示例。不幸的是,我没有找到任何全面详细介绍两者之间差异的示例。
我的好奇心起源于为什么BinaryFormatter能够直接反序列化接口,而XmlSerializer则不能。Jon Skeet在回答“casting to multiple (unknown types) at runtime”时提供了一个直接二进制序列化到接口的示例。Stan R.在他对“XML Object Deserialization to Interface”的回答中提供了实现我的目标的方法。
除了BinaryFormatter使用二进制序列化,而XmlSerializer使用XML之外,我想更全面地了解它们之间的根本区别。何时使用其中之一以及各自的优缺点。
5个回答

101
一个二进制格式化程序之所以能够直接反序列化为接口类型,是因为当对象最初序列化为二进制流时,包含类型和程序集信息的元数据会与对象数据一起粘贴。这意味着当二进制格式化程序反序列化对象时,它知道其类型,构建正确的对象,然后您可以将其强制转换为该对象实现的接口类型。
另一方面,XML序列化器只序列化到模式,并且仅序列化对象的公共字段和值,没有其他类型信息(例如,类型实现的接口)。
这里有一篇好文章,.NET Serialization,比较了BinaryFormatterSoapFormatterXmlSerializer。我建议您查看以下表格,除了先前提到的序列化程序外,还包括DataContractSerializerNetDataContractSerializerprotobuf-net

Serialization Comparison


1
好的表格。我总是觉得SOAP缺乏泛型很烦人。 - Callum Rogers
5
我认为“最佳性能”分类是错误的。在.NET中,二进制格式化程序是最差的序列化器(除了可能是SOAP格式化程序)。至少大多数基准测试都显示了这一点:http://blogs.msdn.com/b/youssefm/archive/2009/07/10/comparing-the-performance-of-net-serializers.aspx、http://james.newtonking.com/archive/2010/01/01/net-serialization-performance-comparison.aspx、http://techmikael.blogspot.com/2010/01/net-serialization-performance.html。 - joniba
@joniba 我还没有点击阅读所引用的文章,但如果不是二进制格式化程序,哪种序列化工具具有最佳性能? - ahsteele
1
@ahsteele 在这个特定的列表中,首先是Protobuf-net,然后是DataContractSerializer。 - joniba
@CallumRogers,肥皂格式化程序在 .net 2.0 中被 XmlSerializer 取代,因此从未为泛型更新。 - MikeT
2
@joniba 最佳性能始终取决于使用情况,XML 不会重复使用元素,因此任何具有大量共享引用的数据集在 XML 处理中都会有大量重复,这将降低性能,但是使用平面对象进行测试将有利于 XML。 - MikeT

6

仅作为参考意见...

这两者之间显而易见的区别是“二进制 vs XML”,但实际上比这更深入:

  • 字段 (BinaryFormatter=bf) vs 公共成员 (通常是属性) (XmlSerializer=xs)
  • 基于类型元数据 (bf) vs 基于契约 (xs)
  • 版本脆弱 (bf) vs 版本容忍 (xs)
  • “图” (bf) vs “树” (xs)
  • .NET 特定 (bf) vs 可移植 (xs)
  • 不透明 (bf) vs 可读性强 (xs)

关于为什么BinaryFormatter可能会脆弱的讨论,请看这里

讨论哪个更大是不可能的; BinaryFormatter中的所有类型元数据都可以使其变得更大。而XmlSerializer可以很好地使用像gzip这样的压缩。

但是,可以利用每个的优势; 例如,Google开源了他们自己的数据序列化格式,“protocol buffers”。这是:

  • 基于契约
  • 可移植 (参见实现列表)
  • 版本容忍
  • 基于树的
  • 不透明的 (虽然有工具可以在与.proto结合使用时显示数据)
  • 通常是“契约优先”,但某些实现允许基于反射的隐式契约

但重要的是,它是非常密集的数据(没有类型元数据,纯二进制表示,短标签,诸如变长基于7的编码之类的技巧),并且非常高效地处理(没有复杂的xml结构,没有要匹配成员的字符串等)。

我可能有点偏见; 我维护其中一个实现(包括几个适用于C#/.NET的实现),但您会注意到我没有链接到任何特定的实现; 该格式是基于其自身的优点而存在的 ;-p


2
XML序列化器生成XML以及XML Schema(隐式)。它将生成符合此架构的XML。
其中的一个含义是,它不会序列化任何无法用XML Schema描述的内容。例如,在XML Schema中无法区分列表和数组,因此序列化器生成的XML Schema可以用两种方式解释。
运行时序列化(其中BinaryFormatter是其一部分)将实际的.NET类型序列化到另一侧,因此如果您发送一个List<int>,另一侧将得到一个List<int>。
如果另一侧正在运行.NET,则显然效果更好。

嗨John,我只是想知道如果处理List<T>不是问题,你是否仍然更喜欢BinaryFormatter? - paradisonoir
不,列表只是一个例子。这两者有完全不同的用途。顺便说一下,可以看看SoapFormatter。运行时序列化(这两个格式化程序)与XML序列化完全不同,而数据契约序列化也非常不同。 - John Saunders

1

XmlSerializer通过读取所有具有公共getter和setter(以及任何公共字段)的类型属性来序列化类型。在这个意义上,XmlSerializer序列化/反序列化实例的“公共视图”。

相比之下,二进制格式化程序通过序列化实例的“内部”,即其字段,来序列化类型。任何未标记为[NonSerialized]的字段都将被序列化到二进制流中。类型本身必须标记为[Serializable],任何要序列化的内部字段也必须如此。


0

链接已失效且未被归档。 - Martin Schneider

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