WCF探勘15-DataContract與DataMember
3 |
學藝不精,陸續踩了幾次雷,整理DataContract與DataMember對序列化的影響備忘。
WCF預設使用DataContractSerializer執行序列化,而DataContractSerializer可依物件類別標註的[DataContract]及[DataMember]、[IgnoreDataMember]等Attribute決定哪些屬性該序列化。依照MSDN文件,DataContractSerializer的處理原則為:
- 類別標示[DataContract]時,只序列化有標示[DataMember]的項目
註:DataMember不限於public Property,可用於各種存取層級(public、private、internal、protected)的Property或Field。 - 若類別未標示[DataContract],DataContractSerializer預設會序列化「所有可讀寫的public Property及Field」,此時可透過[IgnoreDataMember]負向表列不要序列化的Property或Field。
我設計了以下幾個型別來觀察DataContractSerializer行為,有Property有Field,有public有private,再配合[DataContract]、[DataMember]、[IgnoreDataMember]組合出不同變化:
using System.Runtime.Serialization;
[DataContract]
public class Blah1
{
public int PropNoAttr { get; set; }
public int Field;
private int PrivProp { get; set; }
private int PrivField;
}
[DataContract]
public class Blah2
{
public int PropNoAttr { get; set; }
[DataMember]
public int PropAttr { get; set; }
public int Field;
[DataMember]
private int PrivProp { get; set; }
[DataMember]
private int PrivField;
}
[DataContract]
public class Blah3
{
public int PropNoAttr { get; set; }
[IgnoreDataMember]
public int PropIgnoreAttr { get; set; }
public int Field;
private int PrivProp { get; set; }
private int PrivField;
}
public class Blah4
{
public int PropNoAttr { get; set; }
[DataMember]
public int PropAttr { get; set; }
[IgnoreDataMember]
public int PropIgnoreAttr { get; set; }
public int Field;
private int PrivProp { get; set; }
private int PrivField;
}
public class Blah5
{
public int PropNoAttr { get; set; }
public int ReadonlyProp { get; }
public int Field;
private int PrivProp { get; set; }
private int PrivField;
}
測試程式很簡單,用DataContractSerializer將Blah1到Blah5序列化成XML,Console.WriteLine出來,借用XDocument將XML以縮排格式輸出。
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Serialize<Blah1>(new Blah1()));
Console.WriteLine(Serialize<Blah2>(new Blah2()));
Console.WriteLine(Serialize<Blah3>(new Blah3()));
Console.WriteLine(Serialize<Blah4>(new Blah4()));
Console.WriteLine(Serialize<Blah5>(new Blah5()));
Console.Read();
}
static string Serialize<T>(T graph)
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
MemoryStream ms = new MemoryStream();
dcs.WriteObject(ms, graph);
XDocument xd = XDocument.Parse(Encoding.UTF8.GetString(ms.ToArray()));
return
typeof(T).ToString() +
"\n=====================================\n" +
xd.ToString() + "\n";
}
}
}
執行結果如下:
Blah1
=====================================
<Blah1 xmlns="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
Blah2
=====================================
<Blah2 xmlns="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<PrivField>0</PrivField>
<PrivProp>0</PrivProp>
<PropAttr>0</PropAttr>
</Blah2>
Blah3
=====================================
<Blah3 xmlns="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
Blah4
=====================================
<Blah4 xmlns="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Field>0</Field>
<PropAttr>0</PropAttr>
<PropNoAttr>0</PropNoAttr>
</Blah4>
Blah5
=====================================
<Blah5 xmlns="http://schemas.datacontract.org/2004/07/"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Field>0</Field>
<PropNoAttr>0</PropNoAttr>
</Blah5>
- Blah1
只標了[DataContract]沒標任何[DataMember],XML空空如也,沒有任何Property或Field被序列化 - Blah2
標註[DataContract]後,所有標註[DataMember]的成員都包含在XML中,不論public或private,不管是Property或是Field - Blah3
標註[DataContract]後DataContractSerializer只認[DataMember]辦事,[IgnoreDataMember]沒有作用,XML是空的 - Blah4
未標註[DataContract],除了[IgnoreDataMember] PropIgnoreAttr外,所有public的Property及Field都被序列化 - Blah5
未加任何Attribute,DataContractSerializer將序列化所有公開Property及Field,但Property限定可讀寫者,刻意放了一個public ReadonlyProp { get; }唯讀屬性,果然被排除了。
實驗驗證完畢!
Comments
# by Jonh doe
最後一個blah4 應該是blah5
# by Jeffrey
to John, 一如往例,沒有錯字就不是黑大真跡 orz orz orz。謝謝指正。
# by Carter
Property 似乎不能用 readonly