C#對 Json的序列化和反序列化會出現“k_BackingField”

C#對 Json的序列化和反序列化會出現“k_BackingField

事情從Json的序列化和反序列化說起。

C#2.0的項目中,以前經常使用Json.Net實現序列化和反序列化。後來從c#3.0中開始使用新增的DataContractJsonSerializer進行json相關的操作。微軟提供的原生類庫使用上並不複雜,參考一下msdn你很容易就會寫出序列化和反序列化的方法,比如經常被人使用的泛型方法如下:

 

對象轉換成json

/// <summary>

        /// 對象轉換成json

        /// </summary>

        /// <typeparam name="T"></typeparam>

        /// <param name="jsonObject">需要格式化的對象</param>

        /// <returns>Json字符串</returns>

        public static string DataContractJsonSerialize<T>(T jsonObject)

        {

            var serializer = new DataContractJsonSerializer(typeof(T));

            string json = null;

            using (var ms = new MemoryStream()) //定義一個stream用來存發序列化之後的內容

            {

                serializer.WriteObject(ms, jsonObject);

                var dataBytes = new byte[ms.Length];

                ms.Position = 0;

                ms.Read(dataBytes, 0, (int)ms.Length);

                json = Encoding.UTF8.GetString(dataBytes);

                ms.Close();

            }

            return json;

        }

        /// <summary>

        /// json字符串轉換成對象

        /// </summary>

        /// <typeparam name="T"></typeparam>

        /// <param name="json">要轉換成對象的json字符串</param>

        /// <returns></returns>

        public static T DataContractJsonDeserialize<T>(string json)

        {

            var serializer = new DataContractJsonSerializer(typeof(T));

            var obj = default(T);

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))

            {

                obj = (T)serializer.ReadObject(ms);

                ms.Close();

            }

            return obj;

        }

 

不過使用該類庫方法的過程中還是不慎意外發現了k_BackingField

舉例之前說一下我們的一個簡單的實體類Person,它有如下定義:

Person實體

public class Person

    {

        public int Id { getset; }

        public string FirstName { getset; }

        public string LastName { getset; }

        public DateTime Birthday { getset; }

    }

 

如果Person沒有附加任何特性,經測試,可以成功使用上述泛型方法進行處理。

無特性Serialize

var person = new Person { Id = 1, FirstName = "jeff", LastName = "wong", Birthday = new DateTime(198383) };

            var json = JsonHelper.DataContractJsonSerialize<Person>(person);

            Console.WriteLine(json);

            var result = JsonHelper.DataContractJsonDeserialize<Person>(json);

            if (result != null)

            {

                Console.WriteLine("{0} {1}", result.FirstName, result.LastName);

            }

 

而且json生成是正常的字符串:

{"Birthday":"\/Date(428688000000+0800)\/","FirstName":"jeff","Id":1,"LastName":"wong"}

 

 

可是當我們把Person實體上面設置Serializable特性後,莫名,我就很不解了:

{"<Birthday>k__BackingField":"\/Date(428688000000+0800)\/","<FirstName>k__BackingField":"jeff","<Id>k__BackingField":1,"<LastName>k__BackingField":"wong"}

 

 

搜索了一下,果然早就有人發現了類似的問題。後來上stackoverflow一查,查到好像和自動屬性有點關係,大家可以看一下這一篇這一篇,而且評論比原帖精彩好像國內外大部分都是一致的。

有人說用Reflector反彙編可以看到自動屬性生成的字段有前綴,可惜我一直使用ILSpy,興致勃勃反編譯查看了一下,沒有沒有是真的沒有啊。

到這裏你可能會想到,自動屬性json會有k_BackingField前綴,那傳統那種屬性的寫法呢?

Serializable實體

[Serializable]

    public class Person

    {

        private int id;

        public int Id

        {

            get { return id; }

            set { id = value; }

        }

        private string firstName;

        public string FirstName

        {

            get { return firstName; }

            set { firstName = value; }

        }

        private string lastName;

        public string LastName

        {

            get { return lastName; }

            set { lastName = value; }

        }

        private DateTime birthday;

        public DateTime Birthday

        {

            get { return birthday; }

            set { birthday = value; }

        }

    }

 

OK,我們想一塊去了,經測試,帶Serializable特性的Person類,輸出json一點問題沒有:

{"birthday":"\/Date(428688000000+0800)\/","firstName":"jeff","id":1,"lastName":"wong"}

  

但是,請注意大小寫(我挖了一個坑,上面的json是序列化屬性嗎?首字母有沒有大寫?)。

有沒有兼容方式使自動屬性輸出json也正常呢?很簡單,使用DataContractDataMember屬性,哪一種寫法輸出json都沒有問題的:

DataContract實體

 [DataContract]

    public class Person

    {

        [DataMember]

        public int Id { getset; }

        [DataMember]

        public string FirstName { getset; }

        [DataMember]

        public string LastName { getset; }

        [DataMember]

        public DateTime Birthday { getset; }

    }

 

json輸出帶有k_BackingField前綴的問題可能非常簡單,這裏只是善意地提醒,我個人曾經有過“慘痛”的教訓,而且感覺還相當隱蔽,大家也要小心啊。

最後,在使用.net framework自帶的json有關類庫的時候還碰到過特殊符號和時間格式轉換的問題,網上有不少文章都講到,相信不少人也有類似經歷,這裏就不說了。

 

參考:

http://geekswithblogs.net/sdorman/archive/2007/08/08/C-3.0-Automatic-Properties.aspx

http://stackoverflow.com/questions/945585/c-sharp-automatic-property-deserialization-of-json

http://stackoverflow.com/questions/340528/c-sharp-automatic-properties-why-do-i-have-to-write-get-set

http://www.cnblogs.com/goldarch/archive/2011/04/25/2027071.html

http://computeroverlord.tumblr.com/post/34781472/deserialization-problems-k-backingfield

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章