zoukankan      html  css  js  c++  java
  • 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 { get; set; }
    
            public string FirstName { get; set; }
    
            public string LastName { get; set; }
    
            public DateTime Birthday { get; set; }
        }

    如果Person没有附加任何特性,经测试,可以成功使用上述泛型方法进行处理。

    无特性Serialize
    var person = new Person { Id = 1, FirstName = "jeff", LastName = "wong", Birthday = new DateTime(1983, 8, 3) };
                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 { get; set; }
    
            [DataMember]
            public string FirstName { get; set; }
    
            [DataMember]
            public string LastName { get; set; }
    
            [DataMember]
            public DateTime Birthday { get; set; }
        }

    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

    ============================================================================

    转自:http://www.cnblogs.com/jeffwongishandsome/archive/2012/05/31/2529196.html

  • 相关阅读:
    从零开始入门 K8s | 应用编排与管理
    209. Minimum Size Subarray Sum
    208. Implement Trie (Prefix Tree)
    207. Course Schedule
    203. Remove Linked List Elements
    183. Customers Who Never Order
    182. Duplicate Emails
    181. Employees Earning More Than Their Managers
    1261. Find Elements in a Contaminated Binary Tree
    1260. Shift 2D Grid
  • 原文地址:https://www.cnblogs.com/PLifeCopyDown/p/2681213.html
Copyright © 2011-2022 走看看