前言:作為開發人員,物件的序列化恐怕難以避免。樓主也是很早以前就接觸過序列化,可是理解都不太深刻,對於用哪種方式去做序列化更是隨波逐流——專案中原來用的什麼方式照著用就好了。可是這麼多年自己對於這東西還是挺模糊的,今天正好有時間,就將原來用過的幾種方式總結了下,也算是做一個記錄,順便做了下效能測試。樓主算了下,從使用序列化到現在,用到的無非下面幾種方式:(1)JavaScriptSerializer方式;(2)DataContract方式;(3)Newtonsoft.Json.
1、準備工作:要對這三種方式分別作測試,必須要將相應的內庫引用進來。
(1)JavaScriptSerializer這個類是.Net內建的,屬於System.Web.Script.Serialization這個名稱空間下面。需要引用System.Web.Extensions這個dll。
(2)DataContract方式也是.net內建的,主要使用的DataContractJsonSerializer這個類,屬於System.Runtime.Serialization.Json這個名稱空間。需要引用System.Runtime.Serialization這個dll。
(3)Newtonsoft.Json是第三方的dll,但是Visual Studio 對它做了很好的支援。使用方式有兩種:一種是去網上下載最新的dll,然後新增引用即可;第二種是直接使用NuGet安裝這個包。方式如下:
按照步驟安裝即可。
2、類庫準備完畢,還需要提供幾個通用的方法。自己分別封裝了JavaScriptSerializer和DataContract方式兩個方法,程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#region DataContract序列化 public static class DataContractExtensions { /// <summary> /// 將物件轉化為Json字串 /// </summary> /// <typeparam name="T">物件型別</typeparam> /// <param name="instanse">物件本身</param> /// <returns>JSON字串</returns> public static string ToJsonString<T>(this T instanse) { try { DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream()) { js.WriteObject(ms, instanse); ms.Flush(); ms.Seek(0, SeekOrigin.Begin); StreamReader sr = new StreamReader(ms); return sr.ReadToEnd(); } } catch { return String.Empty; } } /// <summary> /// 將字串轉化為JSON物件,如果轉換失敗,返回default(T) /// </summary> /// <typeparam name="T">物件型別</typeparam> /// <param name="s">字串</param> /// <returns>轉換值</returns> public static T ToJsonObject<T>(this string s) { try { DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream()) { StreamWriter sw = new StreamWriter(ms); sw.Write(s); sw.Flush(); ms.Seek(0, SeekOrigin.Begin); return (T)js.ReadObject(ms); } } catch { return default(T); } } } #endregion #region JavaScriptSerializer方式序列化 public static class JavascriptExtentions { public static string ToScriptJsonString<T>(this T instanse) { try { JavaScriptSerializer js = new JavaScriptSerializer(); return js.Serialize(instanse); } catch { return String.Empty; } } public static T ToScriptJsonObject<T>(this string s) { try { JavaScriptSerializer js = new JavaScriptSerializer(); return js.Deserialize<T>(s); } catch { return default(T); } } } #endregion |
至於Newtonsoft.Json,自己有對應的方法,自己也封裝了幾個方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
public class Newtonsoft_Common { #region 序列化 // 將物件(包含集合物件)序列化為Json public static string SerializeObjToJson(object obj) { string strRes = string.Empty; try { strRes = JsonConvert.SerializeObject(obj); } catch { } return strRes; } //將xml轉換為json public static string SerializeXmlToJson(System.Xml.XmlNode node) { string strRes = string.Empty; try { strRes = JsonConvert.SerializeXmlNode(node); } catch { } return strRes; } //支援Linq格式的xml轉換 public static string SerializeXmlToJson(System.Xml.Linq.XNode node) { string strRes = string.Empty; try { strRes = JsonConvert.SerializeXNode(node); } catch { } return strRes; } #endregion #region 反序列化 //將json反序列化為實體物件(包含DataTable和List<>集合物件) public static T DeserializeJsonToObj<T>(string strJson) { T oRes = default(T); try { oRes = JsonConvert.DeserializeObject<T>(strJson); } catch { } return oRes; } //將Json陣列轉換為實體集合 public static List<T> JsonLstToObjs<T>(List<string> lstJson) { List<T> lstRes = new List<T>(); try { foreach (var strObj in lstJson) { //將json反序列化為物件 var oRes = JsonConvert.DeserializeObject<T>(strObj); lstRes.Add(oRes); } } catch { } return lstRes; } #endregion } |
還有就是提供測試資料的兩個方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
public static List<Person> GetPersons() { var lstRes = new List<Person>(); for (var i = 0; i < 50000; i++) { var oPerson = new Person(); oPerson.Name = "李雷" + i; oPerson.Age = 20; oPerson.IsChild = i % 5 == 0 ? true : false; oPerson.Test1 = "aaaaaa"; oPerson.Test2 = i.ToString() ; oPerson.Test3 = i.ToString(); oPerson.Test4 = i.ToString(); oPerson.Test5 = i.ToString(); oPerson.Test6 = i.ToString(); oPerson.Test7 = i.ToString(); oPerson.Test8 = i.ToString(); oPerson.Test9 = i.ToString(); oPerson.Test10 = i.ToString(); lstRes.Add(oPerson); } return lstRes; } public static DataTable GetDataTable() { var dt = new DataTable("dt"); dt.Columns.Add("Age", Type.GetType("System.Int32")); dt.Columns.Add("Name", Type.GetType("System.String")); dt.Columns.Add("Sex", Type.GetType("System.String")); dt.Columns.Add("IsChild", Type.GetType("System.Boolean")); for (var i = 0; i < 1000; i++) { DataRow dr = dt.NewRow(); dr["Age"] = i + 1; dr["Name"] = "Name" + i; dr["Sex"] = i % 2 == 0 ? "男" : "女"; dr["IsChild"] = i % 5 > 0 ? true : false; dt.Rows.Add(dr); } return dt; } |
3、測試開始之前,先介紹下,本篇測試分別通過強型別物件和若型別的DataTable分別去做序列化和反序列化的測試。測試程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
static void Main(string[] args) { #region 強型別物件 var lstRes = GetPersons(); #region JavaScriptSerializer序列化方式 var lstScriptSerializeObj = new List<string>(); Stopwatch sp_script = new Stopwatch(); sp_script.Start(); foreach (var oPerson in lstRes) { lstScriptSerializeObj.Add(oPerson.ToScriptJsonString<Person>()); } sp_script.Stop(); Console.WriteLine("JavaScriptSerializer序列化方式序列化" + lstScriptSerializeObj.Count + "個物件耗時:" + sp_script.ElapsedMilliseconds + "毫秒"); lstRes.Clear(); Stopwatch sp_script1 = new Stopwatch(); sp_script1.Start(); foreach (var oFrameSerializeObj in lstScriptSerializeObj) { lstRes.Add(oFrameSerializeObj.ToScriptJsonObject<Person>()); } sp_script1.Stop(); Console.WriteLine("JavaScriptSerializer序列化方式反序列化" + lstScriptSerializeObj.Count + "個物件耗時:" + sp_script1.ElapsedMilliseconds + "毫秒"); #endregion #region DataContract序列化方式 var lstFrameSerializeObj = new List<string>(); Stopwatch sp = new Stopwatch(); sp.Start(); foreach (var oPerson in lstRes) { lstFrameSerializeObj.Add(oPerson.ToJsonString<Person>()); } sp.Stop(); Console.WriteLine("DataContract序列化方式序列化" + lstFrameSerializeObj.Count + "個物件耗時:" + sp.ElapsedMilliseconds + "毫秒"); lstRes.Clear(); Stopwatch sp1 = new Stopwatch(); sp1.Start(); foreach (var oFrameSerializeObj in lstFrameSerializeObj) { lstRes.Add(oFrameSerializeObj.ToJsonObject<Person>()); } sp1.Stop(); Console.WriteLine("DataContract序列化方式反序列化" + lstFrameSerializeObj.Count + "個物件耗時:" + sp1.ElapsedMilliseconds + "毫秒"); #endregion #region Newtonsoft var lstNewtonsoftSerialize = new List<string>(); Stopwatch sp2 = new Stopwatch(); sp2.Start(); foreach (var oPerson in lstRes) { lstNewtonsoftSerialize.Add(JsonConvert.SerializeObject(oPerson)); } sp2.Stop(); Console.WriteLine("Newtonsoft.Json方式序列化" + lstNewtonsoftSerialize.Count + "個物件耗時:" + sp2.ElapsedMilliseconds + "毫秒"); lstRes.Clear(); Stopwatch sp3 = new Stopwatch(); sp3.Start(); foreach (var oNewtonsoft in lstNewtonsoftSerialize) { lstRes.Add(JsonConvert.DeserializeObject<Person>(oNewtonsoft)); } sp3.Stop(); Console.WriteLine("Newtonsoft.Json方式反序列化" + lstNewtonsoftSerialize.Count + "個物件耗時:" + sp3.ElapsedMilliseconds + "毫秒"); #endregion #endregion #region 弱型別DataTable /*var dt = GetDataTable(); #region JavaScriptSerializer序列化方式 var lstScriptSerializeObj = new List<string>(); Stopwatch sp_script = new Stopwatch(); sp_script.Start(); var strRes = dt.ToScriptJsonString<DataTable>(); sp_script.Stop(); Console.WriteLine("JavaScriptSerializer序列化方式序列化" + lstScriptSerializeObj.Count + "個物件耗時:" + sp_script.ElapsedMilliseconds + "毫秒"); dt.Clear(); Stopwatch sp_script1 = new Stopwatch(); sp_script1.Start(); dt = strRes.ToScriptJsonObject<DataTable>(); sp_script1.Stop(); Console.WriteLine("JavaScriptSerializer序列化方式反序列化" + lstScriptSerializeObj.Count + "個物件耗時:" + sp_script1.ElapsedMilliseconds + "毫秒"); #endregion #region DataContract序列化方式 var lstFrameSerializeObj = new List<string>(); Stopwatch sp = new Stopwatch(); sp.Start(); strRes = dt.ToJsonString<DataTable>(); sp.Stop(); Console.WriteLine("DataContract序列化方式序列化" + lstFrameSerializeObj.Count + "個物件耗時:" + sp.ElapsedMilliseconds + "毫秒"); dt.Clear(); Stopwatch sp1 = new Stopwatch(); sp1.Start(); dt = strRes.ToJsonObject<DataTable>(); sp1.Stop(); Console.WriteLine("DataContract序列化方式反序列化" + lstFrameSerializeObj.Count + "個物件耗時:" + sp1.ElapsedMilliseconds + "毫秒"); #endregion #region Newtonsoft var lstNewtonsoftSerialize = new List<string>(); Stopwatch sp2 = new Stopwatch(); sp2.Start(); strRes = JsonConvert.SerializeObject(dt); sp2.Stop(); Console.WriteLine("Newtonsoft.Json方式序列化" + lstNewtonsoftSerialize.Count + "個物件耗時:" + sp2.ElapsedMilliseconds + "毫秒"); dt.Clear(); Stopwatch sp3 = new Stopwatch(); sp3.Start(); dt = JsonConvert.DeserializeObject<DataTable>(strRes); sp3.Stop(); Console.WriteLine("Newtonsoft.Json方式反序列化" + lstNewtonsoftSerialize.Count + "個物件耗時:" + sp3.ElapsedMilliseconds + "毫秒"); #endregion*/ #endregion Console.ReadLine(); } |
4、測試結果:
先說強型別物件的結果:
(1)集合數量100和1000時,序列化和反序列化三種方式差別不大:
(2)當超過10000時,
(3)繼續加大資料量
弱型別DataTable的測試結果:
JavaScriptSerializer方式直接報錯:
DataContract方式需要提供DataTable的表名,序列化得到是DataTable的Xml
Newtonsoft.Json方式可以實現和Json資料的序列化和反序列化。
5、測試總結:
(1)總的來說,DataContract和Newtonsoft.Json這兩種方式效率差別不大,隨著數量的增加JavaScriptSerializer的效率相對來說會低些。
(2)對於DataTable的序列化,如果要使用json資料通訊,使用Newtonsoft.Json更合適,如果是用xml做持久化,使用DataContract合適。
(3)隨著數量的增加JavaScriptSerializer序列化效率越來越低,反序列化和其他兩種相差不大。
(4)後來發現當物件的DataTime型別屬性不賦值時,DataContract和JavaScriptSerializer這兩種方式序列化都會報錯,而用Newtonsoft.Json方式可以正常序列化。所以看來在容錯方便,還是Newtonsoft.Json比較強。
以上只是樓主自己做的簡單測試,可能存在不夠嚴謹的地方,望各位大蝦拍磚指正~~
附上原始碼:原始碼下載。