XMLSerializer 是早期 ASMX Web Service 預設的序列化器,許多開發者對它並不陌生。為了理解其映射機制,我們先透過範例觀察 Managed Type 結構與生成 XML 的對應關係。範例中定義了 XMLProduct 與 XMLOrder 兩個類別,其成員結構與前一篇提到的 DataContract 版本相同。
以下程式碼示範如何使用 XMLSerializer 進行序列化:
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="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://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>
由此可總結 XMLSerializer 的預設映射規則:
internal string ProducingArea 就被忽略)。與 DataContractSerializer 類似,XMLSerializer 也提供屬性來調整預設行為:
[XmlRoot]:指定根元素名稱與命名空間。[XmlElement] 與 [XmlAttribute]:控制成員輸出為元素或屬性,並可設定名稱、命名空間與順序(Order 參數)。[XmlIgnore]:排除特定成員不參與序列化。套用屬性後的類別定義如下:
[XmlRoot(Namespace = "https://artech.wcfSerialization/Samples/Order")]
public class XMLOrder
{
[XmlAttribute("id")]
public Guid OrderID { get; set; }
[XmlElement(ElementName = "date", Order = 3)]
public DateTime OrderDate { get; set; }
[XmlElement(ElementName = "product", Order = 1, Namespace = "Http://Artech.WCFSerialization/Samples/Product")]
public XMLProduct Product { get; set; }
[XmlElement(ElementName = "quantity", Order = 2)]
public int Quantity { get; set; }
// ... 建構函式與 ToString 省略
}
public class XMLProduct
{
[XmlAttribute("id")]
public Guid ProductID { get; set; }
[XmlElement("name")]
public string ProductName { get; set; }
[XmlElement("producingArea")]
public string ProducingArea { get; set; }
[XmlElement("price")]
public double UnitPrice { get; set; }
// ... 建構函式省略
}
再次序列化後,XML 結構變更為:
<?xml version="1.0" encoding="utf-8"?>
<XMLOrder id="9a0bbda4-1743-4398-bc4f-ee216e02695b" xmlns="https://artech.wcfSerialization/Samples/Order" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://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>
反序列化程式碼如下:
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), "https://artech.WCFSerialization/Samples");
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas()))
{
order = serializer.Deserialize(reader) as XMLOrder;
}
}
Console.WriteLine(order);
Console.Read();
}
執行結果顯示,反序列化時會呼叫無參數建構函式(輸出 "The constructor of XMLProduct has been invocated!" 等訊息)。這與 DataContractSerializer 不會呼叫建構函式 形成鮮明對比。
| 特性 | XMLSerializer | DataContractSerializer |
|---|---|---|
| 預設映射對象 | 所有 public 欄位與可讀寫屬性 | 標記 [DataMember] 的欄位/屬性 |
| 是否需屬性 | 不需要 | 需 [DataContract] 與 [DataMember](或 [Serializable]) |
| 成員預設順序 | 類別定義順序 | 字母排序 |
| 相容性 | ASMX、Remoting | WCF 預設 |
| 反序列化是否呼叫建構函式 | 是 | 否 |
選擇哪種序列化器取決於專案需求:若需與舊版 ASMX 相容或需精細控制 XML 結構(如屬性與元素混用),XMLSerializer 較適合;若追求效能、支援版本容忍、且不需呼叫建構函式,DataContractSerializer 則是 WCF 的首選。