XMLSerializer
提到XMLSerializer,我想绝大多数人都知道这是asmx采用的Serializer。首先我们还是来看一个例子,通过比较Managed Type的结构和生成的XML的结构来总结这种序列化方式采用的是怎样的一种Mapping方式。和DataContractSerialzer Sample一样,我们要定义用于序列化对象所属的Type——XMLOrder和XMLProduct,他们和相面对应的DataContractOrder和DataContractProduct具有相同的成员。
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Artech.WCFSerialization
{ public class XMLProduct { Private Fields #region Private Fields private Guid _productID; private string _productName; private string _producingArea; private double _unitPrice; Constructors #region Constructors public XMLProduct() { Console.WriteLine( " The constructor of XMLProduct has been invocated! " ); } public XMLProduct(Guid id, string name, string producingArea, double price) { this ._productID = id; this ._productName = name; this ._producingArea = producingArea; this ._unitPrice = price; } #endregion Properties #region Properties public Guid ProductID { get { return _productID; } set { _productID = value; } } public string ProductName { get { return _productName; } set { _productName = value; } } internal string ProducingArea { get { return _producingArea; } set { _producingArea = value; } } public double UnitPrice { get { return _unitPrice; } set { _unitPrice = value; } } #endregion } }
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Artech.WCFSerialization
{ public class XMLOrder { private Guid _orderID; private DateTime _orderDate; private XMLProduct _product; private int _quantity; Constructors #region Constructors public XMLOrder() { this ._orderID = new Guid(); this ._orderDate = DateTime.MinValue; this ._quantity = int .MinValue; Console.WriteLine( " The constructor of XMLOrder has been invocated! " ); } public XMLOrder(Guid id, DateTime date, XMLProduct product, int quantity) { this ._orderID = id; this ._orderDate = date; this ._product = product; this ._quantity = quantity; } #endregion Properties #region Properties public Guid OrderID { get { return _orderID; } set { _orderID = value; } } public DateTime OrderDate { get { return _orderDate; } set { _orderDate = value; } } public XMLProduct Product { get { return _product; } set { _product = value; } } public int Quantity { get { return _quantity; } set { _quantity = value; } } #endregion public override string ToString() { return string .Format( " ID: {0}/nDate:{1}/nProduct:/n/tID:{2}/n/tName:{3}/n/tProducing Area:{4}/n/tPrice:{5}/nQuantity:{6} " , this ._orderID, this ._orderDate, this ._product.ProductID, this ._product.ProductName, this ._product.ProducingArea, this ._product.UnitPrice, this ._quantity); } } }
编写Serialization的Code.
static void SerializeViaXMLSerializer() { XMLProduct product = new XMLProduct(Guid.NewGuid(), " Dell PC " , " Xiamen FuJian " , 4500 ); XMLOrder order = new XMLOrder(Guid.NewGuid(), DateTime.Today, product, 300 ); string fileName = _basePath + " Order.XmlSerializer.xml " ; using (FileStream fs = new FileStream(fileName, FileMode.Create)) { XmlSerializer serializer = new XmlSerializer( typeof (XMLOrder)); using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs)) { serializer.Serialize(writer, order); } } Process.Start(fileName); }
调用上面定义的方法,生成序列化的XML。
<?
xml version="1.0" encoding="utf-8"
?>
<
XMLOrder
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd
="http://www.w3.org/2001/XMLSchema"
>
<
OrderID
>
b695fd18-9cd7-4792-968a-0c0c3a3962c2
</
OrderID
>
<
OrderDate
>
2007-03-09T00:00:00+08:00
</
OrderDate
>
<
Product
>
<
ProductID
>
23a2fe03-d0a0-4ce5-b213-c7e5196af566
</
ProductID
>
<
ProductName
>
Dell PC
</
ProductName
>
<
UnitPrice
>
4500
</
UnitPrice
>
</
Product
>
<
Quantity
>
300
</
Quantity
>
</
XMLOrder
>
这里我们总结出以下的Mapping关系:
Root Element被指定为类名。
不会再Root Element中添加相应的Namaspace。
对象成员以XML Element的形式输出。
对象成员出现的顺利和在Type定义的顺序一致。
只有Public Field和可读可写得Proppery才会被序列化到XML中——比如定义在XMLProduct中的internal string ProducingArea没有出现在XML中。
Type定义的时候不需要运用任何Attribute。
以上这些都是默认的Mapping关系,同DataContractSerializer一样,我们可以通过在Type以及它的成员中运用一些Attribute来改这种默认的Mapping。
Root Element名称之后能为类名。
可以在Type上运用XMLRoot,通过Namaspace参数在Root Element指定Namespace。
可以通过在类成员上运用XMLElement Attribute和XMLAttribute Attribute指定对象成员转化成XMLElement还是XMLAttribute。并且可以通过NameSpace参数定义Namespace。
可以在XMLElement或者XMLAttribute Attribute 通过Order参数指定成员在XML出现的位置。
可以通过XmlIgnore attribute阻止对象成员被序列化。
基于上面这些,我们重新定义了XMLProduct和XMLOrder。
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Xml.Serialization;
namespace
Artech.WCFSerialization
{ public class XMLProduct { Private Fields #region Private Fields private Guid _productID; private string _productName; private string _producingArea; private double _unitPrice; #endregion Constructors #region Constructors public XMLProduct() { Console.WriteLine( " The constructor of XMLProduct has been invocated! " ); } public XMLProduct(Guid id, string name, string producingArea, double price) { this ._productID = id; this ._productName = name; this ._producingArea = producingArea; this ._unitPrice = price; } #endregion Properties #region Properties [XmlAttribute(" id " )] public Guid ProductID { get { return _productID; } set { _productID = value; } } [XmlElement(" name " )] public string ProductName { get { return _productName; } set { _productName = value; } } [XmlElement(" producingArea " )] public string ProducingArea { get { return _producingArea; } set { _producingArea = value; } } [XmlElement(" price " )] public double UnitPrice { get { return _unitPrice; } set { _unitPrice = value; } }#endregion } }
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Xml.Serialization;
namespace
Artech.WCFSerialization
{ [XmlRoot(Namespace = " http://artech.wcfSerialization/Samples/Order " )] public class XMLOrder { private Guid _orderID; private DateTime _orderDate; private XMLProduct _product; private int _quantity; Constructors #region Constructors public XMLOrder() { this ._orderID = new Guid(); this ._orderDate = DateTime.MinValue; this ._quantity = int .MinValue; Console.WriteLine( " The constructor of XMLOrder has been invocated! " ); } public XMLOrder(Guid id, DateTime date, XMLProduct product, int quantity) { this ._orderID = id; this ._orderDate = date; this ._product = product; this ._quantity = quantity; } #endregion Properties #region Properties [XmlAttribute(" id " )] public Guid OrderID { get { return _orderID; } set { _orderID = value; } } [XmlElement(ElementName = " date " ,Order = 3 )] public DateTime OrderDate { get { return _orderDate; } set { _orderDate = value; } } [XmlElement(ElementName = " product " , Order = 1 , Namespace = " Http://Artech.WCFSerialization/Samples/Product " )] public XMLProduct Product { get { return _product; } set { _product = value; } } [XmlElement(ElementName = " quantity " , Order = 2 )] public int Quantity { get { return _quantity; } set { _quantity = value; } } #endregion public override string ToString() { return string .Format( " ID: {0}/nDate:{1}/nProduct:/n/tID:{2}/n/tName:{3}/n/tProducing Area:{4}/n/tPrice:{5}/nQuantity:{6} " , this ._orderID, this ._orderDate, this ._product.ProductID, this ._product.ProductName, this ._product.ProducingArea, this ._product.UnitPrice, this ._quantity); } } }
重新进行一次Serialization。我们可以得到下面的XML。
<?
xml version="1.0" encoding="utf-8"
?>
<
XMLOrder
id
="9a0bbda4-1743-4398-bc4f-ee216e02695b"
xmlns
="http://artech.wcfSerialization/Samples/Order"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd
="http://www.w3.org/2001/XMLSchema"
>
<
product
id
="4e3aabe5-3a51-4000-9fd8-d821d164572a"
xmlns
="Http://Artech.WCFSerialization/Samples/Product"
>
<
name
>
Dell PC
</
name
>
<
producingArea
>
Xiamen FuJian
</
producingArea
>
<
price
>
4500
</
price
>
</
product
>
<
quantity
>
300
</
quantity
>
<
date
>
2007-03-09T00:00:00+08:00
</
date
>
</
XMLOrder
>
分析完XMLSerializer的Serialization功能,我们照例来分析它的反向过程—Deserialization。下面的Deserialization的Code。
static void DeserializeViaXMLSerializer() { string fileName = _basePath + " Order.XmlSerializer.xml " ; XMLOrder order; using (FileStream fs = new FileStream(fileName, FileMode.Open)) { XmlSerializer serializer = new XmlSerializer( typeof (XMLOrder), " http://artech.WCFSerialization/Samples " ); using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas())) { order = serializer.Deserialize(reader) as XMLOrder; } } Console.WriteLine(order); Console.Read(); }
调用DeserializeViaXMLSerializer,得到下面的Screen Shot。下面显示的Order对象的信息和我们利用DataContractSerializaer进行Deserialization是的输出没有什么两样。不过有趣的是上面多出了两行额外的输出:The constructor of XMLProduct has been invocated! The constructor of XMLOrder has been invocated。而这个操作实际上是定义在XMLProduct和XMLOrder的默认(无参)构造函数里的。所此我们可以得出这样的结论——用XMLSerializer进程Deserialization,会调用的默认(无参)构造函数来初始化对象。
DataContractSerializer V.S. XMLSerializer
上面我们分别分析了两种不同的Serializer,现在我们来简单总结一下他们的区别:
特性
XMLSerializer
DataContractSerializer
默认Mapping
所有Public Field和可读可写Property
所有DataMember Filed、Property
是否需要Attribute
不需要
DataContract DataMember或者Serializable
成员的默认次序
Type中定义的顺序
字母排序
兼容性
.asmx
Remoting
Deserialzation
调用默认构造函数
不会调用