本文講講一些純技術的東西。並且講講一些原理性的東西,和一般的百度的文章不一致,如果你對序列化不清楚,絕對可以很有收獲。

ok,我們先建一個控制台項目:

安裝 Newtonsoft.Json 組件

ok,安裝完成之后,我們來講講序列化的本質:
為什么需要序列化?
要理解這個問題很關鍵。很多事就會豁然開朗,與其講為什么序列化,不如我們先來看看一個例子:
我們存儲了一條字符串的數據到文件
我們可能會這么寫
public static void SaveString(string str )
{
using(System.IO.StreamWriter sw = new System.IO.StreamWriter( "123.txt", false, Encoding.Default ))
{
sw.Write( str );
}
}
然后讀取你存儲的數據時候,會這么讀
public static string ReadString( )
{
using (System.IO.StreamReader sr = new System.IO.StreamReader( "123.txt", Encoding.Default ))
{
return sr.ReadToEnd( );
}
}
其實這里的代碼已經實現了最基本的序列化功能。如果你覺得存儲string很簡單,那么來存儲一個int[]數組把。將整個數據存儲到文件,然后讀取加載
public static void SaveIntArray( int[] value )
{
byte[] buffer = new byte[value.Length * 4];
for (int i = 0; i < value.Length; i++)
{
BitConverter.GetBytes( value[i] ).CopyTo( buffer, i * 4 );
}
System.IO.File.WriteAllBytes( "1234.txt", buffer );
}
然后加載的步驟是
public static int[] ReadIntArray( )
{
byte[] buffer = System.IO.File.ReadAllBytes( "1234.txt" );
int[] value = new int[buffer.Length / 4];
for (int i = 0; i < value.Length; i++)
{
value[i] = BitConverter.ToInt32( buffer, i * 4 );
}
return value;
}
上述的兩個示例展示了最基本的序列化和反序列化操作。我們實現序列化和反序列通常是用於寫入文件,加載數據,發送到網絡,從網絡接收數據。
這個就是我們最大的需求了。
實際復雜的數據
比如我們有一串復雜的數據,需要寫文件,或是收發網絡,寫文件和收發網絡的本質是讀寫byte[]數組。而byte[]數組和string是幾乎等效的,可以相互轉換。很多的文件寫入,或是網絡收發都是支持支持string的
所以我們的序列化和反序列化的本質就是實際的數據和string的相互轉換。
比如這個數據對象
public class Account
{
public string UserName { get; set; }
public string Password { get; set; }
public int Age { get; set; }
public string Phone { get; set; }
public double Stature { get; set; }
}
要把這個數據對象轉換成string,然后支持轉換回來,應該怎么操作呢?
接下來就是干貨了
XML序列化及,反序列化
直接上代碼:
public class Account
{
public string UserName { get; set; }
public string Password { get; set; }
public int Age { get; set; }
public string Phone { get; set; }
public double Stature { get; set; }
public string toXml( )
{
System.Xml.Linq.XElement element = new System.Xml.Linq.XElement( "Account" );
element.SetElementValue( nameof( UserName ), UserName );
element.SetElementValue( nameof( Password ), Password );
element.SetElementValue( nameof( Age ), Age.ToString() );
element.SetElementValue( nameof( Phone ), Phone );
element.SetElementValue( nameof( Stature ), Stature.ToString( ) );
return element.ToString( );
}
public void LoadByXml( string data )
{
System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse( data );
UserName = element.Element( nameof( UserName ) ).Value;
Password = element.Element( nameof( Password ) ).Value;
Age = int.Parse( element.Element( nameof( Age ) ).Value );
Phone = element.Element( nameof( Phone ) ).Value;
Stature = double.Parse( element.Element( nameof( Stature ) ).Value );
}
}
我們改造一下就可以了,現在這個類支持了序列化及反序列了,我們看看控制台輸出了什么?
static void Main( string[] args )
{
Account account = new Account( )
{
UserName = "張三",
Password = "123456",
Age = 25,
Phone = "12345678901",
Stature = 170.2d
};
Console.WriteLine( account.toXml( ) );
Console.ReadLine( );
}
看看控制台:

輸出了我們想要的字符串信息。好了,接下來,我們看看JSON格式的數據
JSON序列化及反序列化
json因為庫的方便性,所以不需要寫多余的代碼了
static void Main( string[] args )
{
Account account = new Account( )
{
UserName = "張三",
Password = "123456",
Age = 25,
Phone = "12345678901",
Stature = 170.2d
};
//Console.WriteLine( account.toXml( ) );
Console.WriteLine( JObject.FromObject( account ).ToString( ) );
Console.ReadLine( );
}
輸出

靈活的操作
現在有個小問題,密碼部分的內容我不想支持序列化,或是換句話說,密碼的信息在序列化的時候忽略。那么類改成下面即可
public class Account
{
public string UserName { get; set; }
[Newtonsoft.Json.JsonIgnore]
public string Password { get; set; }
public int Age { get; set; }
public string Phone { get; set; }
public double Stature { get; set; }
public string toXml( )
{
System.Xml.Linq.XElement element = new System.Xml.Linq.XElement( "Account" );
element.SetElementValue( nameof( UserName ), UserName );
//element.SetElementValue( nameof( Password ), Password );
element.SetElementValue( nameof( Age ), Age.ToString() );
element.SetElementValue( nameof( Phone ), Phone );
element.SetElementValue( nameof( Stature ), Stature.ToString( ) );
return element.ToString( );
}
public void LoadByXml( string data )
{
System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse( data );
UserName = element.Element( nameof( UserName ) ).Value;
//Password = element.Element( nameof( Password ) ).Value;
Age = int.Parse( element.Element( nameof( Age ) ).Value );
Phone = element.Element( nameof( Phone ) ).Value;
Stature = double.Parse( element.Element( nameof( Stature ) ).Value );
}
}
這樣就忽略了密碼的xml序列化和json的序列化
xml支持子元素和特性,內容存儲上更加的豐富,json更加直接一點,內容精簡一點,json也可以寫成上述的xml靈活的方法,這樣就支持任意格式對象的序列化和反序列化了。
public class Account
{
public string UserName { get; set; }
[Newtonsoft.Json.JsonIgnore]
public string Password { get; set; }
public int Age { get; set; }
public string Phone { get; set; }
public double Stature { get; set; }
public string toXml( )
{
System.Xml.Linq.XElement element = new System.Xml.Linq.XElement( "Account" );
element.SetElementValue( nameof( UserName ), UserName );
//element.SetElementValue( nameof( Password ), Password );
element.SetElementValue( nameof( Age ), Age.ToString() );
element.SetElementValue( nameof( Phone ), Phone );
element.SetElementValue( nameof( Stature ), Stature.ToString( ) );
return element.ToString( );
}
public void LoadByXml( string data )
{
System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse( data );
UserName = element.Element( nameof( UserName ) ).Value;
//Password = element.Element( nameof( Password ) ).Value;
Age = int.Parse( element.Element( nameof( Age ) ).Value );
Phone = element.Element( nameof( Phone ) ).Value;
Stature = double.Parse( element.Element( nameof( Stature ) ).Value );
}
public string toJson( )
{
JObject json = new JObject( );
//json.Add( nameof( Password ), new JValue( Password ) );
json.Add( nameof( UserName ), new JValue( UserName ) );
json.Add( nameof( Age ), new JValue( Age ) );
json.Add( nameof( Phone ), new JValue( Phone ) );
json.Add( nameof( Stature ), new JValue( Stature ) );
return json.ToString( );
}
public void LoadByJson(string data )
{
JObject json = JObject.Parse( data );
UserName = json[nameof( UserName )].Value<string>( );
//Password = json[nameof( Password )].Value<string>( );
Age = json[nameof( Age )].Value<int>( );
Phone = json[nameof( Phone )].Value<string>( );
Stature = json[nameof( Stature )].Value<double>( );
}
}
這樣也能實現任意的序列化操作,甚至針對其中某個屬性進行加密解密都可以。
性能對比(具體時間取決於電腦性能,我的cpu : i5-4590 內存 ddr3-1600)
兩種序列化都有適合的場景,此處演示下序列化1W次的性能對比,看看性能差異
static void Main( string[] args )
{
Account account = new Account( )
{
UserName = "張三",
Password = "123456",
Age = 25,
Phone = "12345678901",
Stature = 170.2d
};
DateTime start = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
string value = account.toXml( );
;
}
Console.WriteLine( "Time:" + (DateTime.Now - start).TotalMilliseconds );
start = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
string value = JObject.FromObject( account ).ToString( );
;
}
Console.WriteLine( "Time:" + (DateTime.Now - start).TotalMilliseconds );
start = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
string value = account.toJson( );
;
}
Console.WriteLine( "Time:" + (DateTime.Now - start).TotalMilliseconds );
Console.ReadLine( );
}
第一次運行:

第二次運行:

第三次運行:

接下來加上解析部分
{
Account account = new Account( )
{
UserName = "張三",
Password = "123456",
Age = 25,
Phone = "12345678901",
Stature = 170.2d
};
DateTime start = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
string value = account.toXml( );
Account account1 = new Account( );
account1.LoadByXml( value );
}
Console.WriteLine( "Time:" + (DateTime.Now - start).TotalMilliseconds );
start = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
string value = JObject.FromObject( account ).ToString( );
Account account1 = JObject.Parse( value ).ToObject<Account>( );
}
Console.WriteLine( "Time:" + (DateTime.Now - start).TotalMilliseconds );
start = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
string value = account.toJson( );
Account account1 = new Account( );
account1.LoadByJson( value );
}
Console.WriteLine( "Time:" + (DateTime.Now - start).TotalMilliseconds );
Console.ReadLine( );
}
我們再來看看運行結果:

第二次運行結果:

第三次結果:

終極性能PK
如果我們自己來寫json的序列化呢?
public class Account
{
public string UserName { get; set; }
[Newtonsoft.Json.JsonIgnore]
public string Password { get; set; }
public int Age { get; set; }
public string Phone { get; set; }
public double Stature { get; set; }
public string toXml( )
{
System.Xml.Linq.XElement element = new System.Xml.Linq.XElement( "Account" );
element.SetElementValue( nameof( UserName ), UserName );
//element.SetElementValue( nameof( Password ), Password );
element.SetElementValue( nameof( Age ), Age.ToString() );
element.SetElementValue( nameof( Phone ), Phone );
element.SetElementValue( nameof( Stature ), Stature.ToString( ) );
return element.ToString( );
}
public void LoadByXml( string data )
{
System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse( data );
UserName = element.Element( nameof( UserName ) ).Value;
//Password = element.Element( nameof( Password ) ).Value;
Age = int.Parse( element.Element( nameof( Age ) ).Value );
Phone = element.Element( nameof( Phone ) ).Value;
Stature = double.Parse( element.Element( nameof( Stature ) ).Value );
}
public string toJson( )
{
JObject json = new JObject( );
//json.Add( nameof( Password ), new JValue( Password ) );
json.Add( nameof( UserName ), new JValue( UserName ) );
json.Add( nameof( Age ), new JValue( Age ) );
json.Add( nameof( Phone ), new JValue( Phone ) );
json.Add( nameof( Stature ), new JValue( Stature ) );
return json.ToString( );
}
public void LoadByJson(string data )
{
JObject json = JObject.Parse( data );
UserName = json[nameof( UserName )].Value<string>( );
//Password = json[nameof( Password )].Value<string>( );
Age = json[nameof( Age )].Value<int>( );
Phone = json[nameof( Phone )].Value<string>( );
Stature = json[nameof( Stature )].Value<double>( );
}
public string toMyJson( )
{
StringBuilder sb = new StringBuilder( );
sb.Append( "{" );
sb.Append( Environment.NewLine );
sb.Append( $" \"{nameof( UserName )}\":" );
sb.Append( $"\"{ UserName.Replace( "\"", "\\\"" )}\"," );
sb.Append( Environment.NewLine );
sb.Append( $" \"{nameof( Password )}\":" );
sb.Append( $"\"{ Password.Replace( "\"", "\\\"" ) }\"," );
sb.Append( Environment.NewLine );
sb.Append( $" \"{nameof( Age )}\":" );
sb.Append( $"{Age}," );
sb.Append( Environment.NewLine );
sb.Append( $" \"{nameof( Phone )}\":" );
sb.Append( $"\"{ Phone.Replace( "\"", "\\\"" )}\"," );
sb.Append( Environment.NewLine );
sb.Append( $" \"{nameof( Stature )}\":" );
sb.Append( $"{Stature}," );
sb.Append( Environment.NewLine );
sb.Append( "}" );
return sb.ToString( );
}
}
上述的方法 toMyJson 就是我們所寫的一個方法名稱,這個方法會主動進行序列化,里面也考慮了,如果字符串數據帶有"的情況,需要進行替換 \" 的情況,我們單獨運行這個序列化的方法10000次



所以關於性能,可以大致做個參考
以上的結果只能參照一下,寫法上大家可以根據自己的需求來選擇,性能上肯定會有所差別的。感謝閱讀:

