C# 序列化詳解,xml序列化,json序列化對比


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

 

 

 

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次

 

 

 

 

 所以關於性能,可以大致做個參考

 

 

 

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

打賞

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM