目錄:數組
類型序列化的前提函數
格式化器序列化原理this
控制序列化和反序列化spa
1、序列化、反序列化3d
字節流序列化是將一個對象轉換成一個字節流的過程。code
字節流反序列化是將一個字節流轉回一個對象的過程。orm
--------序列化----------對象
對象:pblog
List<string> p = new List<string>() { "Sun", "Mon", "Star" };
載體:序列化後的字節流載體 ms繼承
System.IO.MemoryStream ms = new System.IO.MemoryStream();
格式化器:序列化工做的工人 formatter
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
序列化:將 p 進行序列化成字節流 ms
formatter.Serialize(ms, p);
-----反序列化------
ms.Position=0; formatter.Deserialize(ms);
實例應用之一:深拷貝
[Serializable]
internal class Product:ICloneable { public string Name { get; set; } public int Age { get; set; } public NumberFlag Number { get; set; } public object Clone() { return this.MemberwiseClone(); } public Product DeepClone() { using (System.IO.Stream ms = new System.IO.MemoryStream()) { System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); formatter.Context = new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone); formatter.Serialize(ms, this); ms.Position = 0; return formatter.Deserialize(ms) as Product; } } } [Serializable] internal class NumberFlag { public string Num { get; set; } }
首先咱們瞭解淺拷貝,拷貝的對象中的引用類型的值的改變會互相影響:
Product p1 = new Product() { Name = "1", Age = 1, Number = new NumberFlag() { Num="01"} }; var p2 = p1.Clone() as Product; if (p2 != null) { p2.Number.Num = "22"; Console.WriteLine("p1 Number:{0}.",p1.Number.Num); Console.WriteLine("p2 Number:{0}.",p2.Number.Num); Console.ReadKey(); }
可是,深拷貝可以解決以上問題:
Product p1 = new Product() { Name = "1", Age = 1, Number = new NumberFlag() { Num="01"} }; var p2 = p1.DeepClone(); if (p2 != null) { p2.Number.Num = "22"; Console.WriteLine("p1 Number:{0}.",p1.Number.Num); Console.WriteLine("p2 Number:{0}.",p2.Number.Num); Console.ReadKey(); }
2、類型序列化的前提
類型默認是不能夠序列化的,須要加上特性 [Serializable]
SerializableAttribute 這個特性只能應用於:引用類型(class)\值類型(struct)\枚舉類型(enum)\委託類型(delegate).
也不能被子類所繼承。
[Serializable] public class Phone { } [Serializable] public class iPhone:Phone { }
3、格式化器序列化原理
爲了實現格式化器的工做,FCL封裝了一個:受保護、不可實例化的類--FormatterServices
System.Runtime.Serialization.FormatterServices
-----格式化器,序列化-------
一、格式化器調用 FormatterServices 的 GetSerializableMembers 方法,這個方法經過反射,返回當前類的成員數組。
public static MemberInfo[] GetSerializableMembers(Type type, StreamingContext context);
二、調用 GetObjectData 方法,返回的是每一個成員對應的本身的值。
public static object[] GetObjectData(object obj, MemberInfo[] members);
三、格式化器,將程序集標識和類型名稱的全名寫入流中。
四、格式化器遍歷以上咱們的獲得的兩個數組:MemberInfo[] 和 object[] ,獲得成員和成員對應值,並寫入流中。
-----格式化器,反序列化--------
一、格式化器讀取程序集名稱和類型名稱,並將程序集標識和類型全名傳遞給方法 GetTypeFromAssembly,返回咱們須要反序列化最終獲得的類型。
public static Type GetTypeFromAssembly(Assembly assem, string name);
二、格式化器,調用GetUninitializedObject方法,對當前類型作一些初始化(不調用構造函數,只是爲成員分配點內存~)
public static object GetUninitializedObject(Type type);
三、也是調用GetSerializableMembers方法,獲取成員 。
四、將流中的數據分配到一個object[]數組中。
五、這樣也是得到了成員數組和對應值的數組。將咱們的新分配的對象、MemberInfo[]、object[],傳入方法,獲取咱們最終的反序列化的類型。
public static object PopulateObjectMembers(object obj, MemberInfo[] members, object[] data);
4、控制序列化和反序列化
一、個別不須要序列化的字段,標記爲:[NonSerialized],此標記只能應用於字段,並可以被子類繼承。
[Serializable] public class TotalTime { public TotalTime(int hours) { HoursofDay = hours; Minutes = hours * 60; } public int HoursofDay; [NonSerialized] public int Minutes; }
那好,咱們進行字節流序列化,沒有問題,正常運行。
TotalTime tt1 = new TotalTime(10); Console.WriteLine("tt1 Minutes:{0}",tt1.Minutes); System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); formatter.Serialize(ms, tt1); ms.Position=0; var tt2= formatter.Deserialize(ms) as TotalTime; Console.WriteLine("tt2 Minutes:{0}", tt2.Minutes); Console.ReadKey();
由於咱們序列化時只有Minutes字段應用了NonSerialized ,因此值就沒有序列化到字節流中。
接下來的反序列化,咱們也就得不到Minutes在序列化以前的那個值:600.
怎麼辦?
[Serializable] public class TotalTime { public TotalTime(int hours) { HoursofDay = hours; Minutes = hours * 60; } public int HoursofDay; [NonSerialized] public int Minutes; [System.Runtime.Serialization.OnDeserialized] private void OnDeserializedMinutes(System.Runtime.Serialization.StreamingContext context) { Minutes = HoursofDay * 60; } }
System.Runtime.Serialization.OnDeserialized 是在反序列化以後的操做。
序列化以前
[System.Runtime.Serialization.OnSerializing]
序列化以後
[System.Runtime.Serialization.OnSerialized]
反序列化以前
[System.Runtime.Serialization.OnDeserializing]
反序列化以後
[System.Runtime.Serialization.OnDeserialized]
已上四個屬性,自定義的方法必須獲取一個流上下文的參數,並返回void,方法的名字咱們能夠自定義。此方法最好是私有,以防外界調用。
主要仍是理解格式化器的流程,對此還能夠控制序列化和反序列化的數據,只要咱們在經過流獲取值數組的那一步進行操做:
public static object[] GetObjectData(object obj, MemberInfo[] members);
--------- 後續會追加Json.Net 的一些對比 ---------
洗刷,洗刷~~~