逛园子时看到Artech兄的[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I ,正好鄙人对WCF也略知一二,于是也来说两句~
大家知道,WCF内置了两种序列化方式,DataContractSerializer和NetDataContractSerializer。WCF的序列化的基本概念Artech兄已经说得很清楚了,在此不再赘述,本文仅就此二者的区别作一番探讨。
先来看看两者的声明:
public sealed class DataContractSerializer : XmlObjectSerializer
{
public DataContractSerializer(Type type);
…
public override object ReadObject(XmlReader reader);
public object ReadObject(Stream stream);
public void WriteObject(Stream stream, object graph);
public override void WriteObject(XmlWriter writer, object graph);
…
}
public sealed class NetDataContractSerializer : XmlObjectSerializer, IFormatter
{
public NetDataContractSerializer();
…
public object Deserialize(Stream stream);
public void Serialize(Stream stream, object graph);
public override object ReadObject(XmlReader reader);
public object ReadObject(Stream stream);
public void WriteObject(Stream stream, object graph);
public override void WriteObject(XmlWriter writer, object graph);
…
}
其中两者的ReadObject(Straem)、WriteObject(Stream, object)的实现继承自基类XmlObjectSerializer,其他方法均为已覆写或实现。
从两个类型的声明中可以看出NetDataContractSerializer实现了IFormatter接口,而DataContractSerializer没有,因此只有NetDataContractSerializer能使用.NET基础结构中的序列化,而DataContractSerializer则是专用于WCF的。
还有一个细节DataContractSerializer的Constructor有一个Type类型的参数,而NetDataContractSerializer没有。这可蕴藏着深意啊,读者接着看就明白了。
现在,再来看看此二者的最大关键区别吧!从一个示例开始吧:
[DataContract]
public class Sub
{
// Fields
[DataMember]
public int Id;
[DataMember]
public string Name;
// Methods
public Sub()
{}
public Sub(int id, string name)
{
this.Id = id;
this.Name = name;
}
}
以上是一个再简单不过的DataContract的,把他给序列化看看出来些啥。
先用DataContractSerializer序列化:
DataContractSerializer dcs = new DataContractSerializer(typeof(Sub));
MemoryStream stream = new MemoryStream();
dcs.WriteObject(stream, sub);
byte[] buf = stream.ToArray();
string str = Encoding.UTF8.GetString(buf, 0, buf.Length);
执行完以上代码后,str的值为:
<Id>10</Id>
<Name>nine</Name>
</Sub>
恩,此SOAP消息那是相当得正常。然后将同一个对象用NetDataContractSerializer序列化:
MemoryStream nstream = new MemoryStream();
ndcs.WriteObject(nstream, sub);
byte[] nbuf = nstream.ToArray();
string nstr = Encoding.UTF8.GetString(nbuf, 0, nbuf.Length);
观察一下nstr的值:
<Sub z:Id="1" z:Type="ServiceInterface.Sub" z:Assembly="ServiceInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns="http://schemas.datacontract.org/2004/07/ServiceInterface" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Id>10</Id>
<Name z:Id="2">nine</Name>
</Sub>
发现了吗?撇开xml命名空间不说,Sub元素多了Type,Assembly和Id,Name属性也多了个Id。信息完整多了~~,现在就可以解释两者Constructor的区别了,DataContractSerializer是按照SOA的datacontract协议(与SOAP基本一直)来序列化对象的,它并不包含平台相关的信息,比如类型,程序集等。所以比如在创建序列化器时就提供将要序列化和反系列化的类型信息,DataContractSerializer无法工作。而NetDataContractSerializer则大大扩充了SOAP,为它添加了程序集、类型名等附加信息,这样一来,序列化器可以完全由序列化的内容来准确推断将要构造的对象,而不必依赖Constructor所提供的类型参数了。这就是两者Constructor不同的原因。
那么z:Id是做什么的呢?嘿嘿,请看下回分解~