-這是我的首個博文,開博的用意在於記載與分享2年工作里一些好用的東西。
-這篇文章主要講述XML與對象的序列化與反序列化。並且會附上一些簡單的序列化與反序列化方法,供大家使用。
假設我們在一個Web項目中有這樣兩個類
public class Member { public string Num { get; set; } public string Name { get; set; } } public class Team { public string Name; public List<Member> Members { get; set; } }
假設我們需要把Team類的一個實例POST到一個URL,
當然,使用Form隱藏域提交就可以完成該功能。
如果該Team包括30條數據呢?
為了區分每個Member,我們得給參數的名字加上后綴。這就要一大串的隱藏域來完成:
<!--使用Razor來演示-->
@model Team <form id="submitForm" action="http://www.johnconnor.com/team" method="post"> <input type="hidden" name="TeamName" value="@Model.Name" /> <input type="hidden" name="MemberNum1" value="@Model.Members[0].Num" /> <input type="hidden" name="MemberName1" value="@Model.Members[0].Name" /> ...
<!--省略28X2個input標簽--> <input type="hidden" name="MemberNum30" value="@Model.Members[29].Num" /> <input type="hidden" name="MemberName30" value="@Model.Members[29].Name" /> </form> <script type="text/javascript"> document.getElementById("submitForm").submit(); </script>
還敢想象一下如果Team再復雜一些,嵌套再多一些的情況么?
呃,即使你願意這么傳數據,對方看到一坨參數名就夠頭疼了。
我們都知道對象是不能在網絡中直接傳輸的,不過還有補救的辦法。
XML(Extensible Markup Language)可擴展標記語言,本身就被設計用來存儲數據,任何一個對象都可以用XML來描述。以Team類為例:
<?xml version="1.0" encoding="utf-8"?> <Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Name>Development</Name> <Members> <Member> <Num>001</Num> <Name>Marry</Name> </Member> <Member> <Num>002</Num> <Name>John</Name> </Member> </Members> </Team>
這樣一個XML文檔就表示了Team一個實例。
聰明的看官應該已經想到,XML是可以作為對象信息的載體在網絡中傳輸,因為它是文本形式的。
怎么進行XML文檔與對象的相互轉換呢?
XmlSerializer類就是干這個活的。
命名空間:System.Xml.Serialization
程序集:System.Xml(在 system.xml.dll 中)
現在這里展示了一個提供序列化與反序列化方法的EncodeHelper類。
Deserialize方法將XML字符串轉換為指定類型的對象;
Serialize方法則將對象轉換為XML字符串。
/// <summary> /// 提供xml文檔序列化 反序列化 /// </summary> public sealed class EncodeHelper { /// <summary> /// 反序列化XML字符串為指定類型 /// </summary> public static object Deserialize(string Xml, Type ThisType) { XmlSerializer xmlSerializer = new XmlSerializer(ThisType); object result; try { using (StringReader stringReader = new StringReader(Xml)) { result = xmlSerializer.Deserialize(stringReader); } } catch (Exception innerException) { bool flag = false; if (Xml != null) { if (Xml.StartsWith(Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()))) { flag = true; } } throw new ApplicationException(string.Format("Couldn't parse XML: '{0}'; Contains BOM: {1}; Type: {2}.",
Xml, flag, ThisType.FullName), innerException); } return result; } /// <summary> /// 序列化object對象為XML字符串 /// </summary> public static string Serialize(object ObjectToSerialize) { string result = null ; try { XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType()); using (MemoryStream memoryStream = new MemoryStream()) { XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(false)); xmlTextWriter.Formatting = Formatting.Indented; xmlSerializer.Serialize(xmlTextWriter, ObjectToSerialize); xmlTextWriter.Flush(); xmlTextWriter.Close(); UTF8Encoding uTF8Encoding = new UTF8Encoding(false, true); result= uTF8Encoding.GetString(memoryStream.ToArray()); } } catch (Exception innerException) { throw new ApplicationException("Couldn't Serialize Object:" + ObjectToSerialize.GetType().Name, innerException); } return result; } }
要使用這個類需要添加以下引用
using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
下面我們用一個控制台程序來演示一下這個類是如何工作的。這里是程序的Main函數。
static void Main(string[] args) { List<Member> Members = new List<Member>(); Member member1 = new Member { Name = "Marry", Num = "001" }; Member member2 = new Member { Name = "John", Num = "002" }; Members.Add(member1); Members.Add(member2); Team team = new Team { Name = "Development", Members = Members }; var xml =EncodeHelper.Serialize(team);//序列化 Console.Write(xml);//打印序列化后的XML字符串 Console.ReadLine(); Team newTeam = EncodeHelper.Deserialize(xml, typeof(Team)) as Team;//反序列化時需要顯式的進行類型轉換 Console.WriteLine("Team Name:"+newTeam.Name);//顯示反序列化后的newTeam對象 foreach (var member in newTeam.Members) { Console.WriteLine("Member Num:" + member.Num); Console.WriteLine("Member Name:" + member.Name); } Console.ReadLine(); }
在執行完Console.Write(xml)這行代碼后,就可以看到打印出來的XML文檔了。
<?xml version="1.0" encoding="utf-8"?> <Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Name>Development</Name> <Members> <Member> <Num>001</Num> <Name>Marry</Name> </Member> <Member> <Num>002</Num> <Name>John</Name> </Member> </Members> </Team>
與我在文章開頭給出的例子是一模一樣的。
最終反序列化出來的newTeam對象打印出來是這樣的結果。
Team Name:Development
Member Num:001
Member Name:Marry
Member Num:002
Member Name:John
回到我們開頭的Web通信的例子,
利用XML序列化與反序列化來進行對象傳遞,我們只需要把需要傳遞的對象序列化為XML字符串,使用一個隱藏域進行form提交就可以搞定咯!
接收方再將接收到的XML字符串反序列化成預設的對象即可。前提是雙方必須約定序列化與反序列化的過程一致,且對象相同。
最后我們來看一下怎么利用一些特性來控制序列化與反序列化操作的過程。我們把開始的類改一下:
public class Member { [XmlElement("Member_Num")] public string Num { get; set; } public string Name { get; set; } } [XmlRoot("Our_Team")] public class Team { [NonSerialized]public string Name;修正於2012-4-13
[XmlIgnore]public string Name; public List<Member> Members { get; set; } }
然后我們再次執行剛才的控制台程序,序列化結果變成了這樣:
<?xml version="1.0" encoding="utf-8"?> <Our_Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Name>Development</Name>修正於2012-4-13 <Members> <Member> <Member_Num>001</Member_Num> <Name>Marry</Name> </Member> <Member> <Member_Num>002</Member_Num> <Name>John</Name> </Member> </Members> </Our_Team>
本來的根節點Team變成了Our_Team,Member的子節點Num變成了Member_Num,並且Team的Name子節點被忽略了。
可見特性XmlRoot可以控制根節點的顯示和操作過程,XmlElement則針對子節點。如果某些成員被標記XmlIgnore NonSerialized修正於2012-4-13特性,則在序列化與反序列化過程中會被忽略。
這些特性的具體內容可以在MSDN查看,就不多講了。
有了這些知識,在網絡中傳遞對象數據應該已經難不倒各位看官了把。^_^
--------------------------------------------------------------我是分割線-----------------------------------------------------------------
2012/4/13修正:感謝3樓的提示。使用 BinaryFormatter 或 SoapFormatter 類序列化對象時,
使用 NonSerializedAttribute 屬性防止字段被序列化。例如,可以使用此屬性防止序列化敏感數據。
如果使用XmlSerializer類序列化對象,則使用XmlIgnoreAttribute 特性獲取相同的功能。