zoukankan      html  css  js  c++  java
  • 认识k_BackingField【转】

    事情从Json的序列化和反序列化说起。

    在C#2.0的项目中,以前经常使用Json.Net实现序列化和反序列化。后来从c#3.0中开始使用新增的DataContractJsonSerializer进行json相关的操作。微软提供的原生类库使用上并不复杂,参考一下msdn你很容易就会写出序列化和反序列化的方法,比如经常被人使用的泛型方法如下:

    public class JsonHelper
    {
        /// <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,它有如下定义:

        public class Person
        {
            public int Id { get; set; }
    
            public string FirstName { get; set; }
    
            public string LastName { get; set; }
    
            public DateTime Birthday { get; set; }
        }

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

    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]
        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也正常呢?很简单,使用DataContract和DataMember属性,哪一种写法输出json都没有问题的:

    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

  • 相关阅读:
    迭代器和生成器
    案例:复制大文件
    案例:使用seek倒查获取日志文件的最后一行
    Leetcode165. Compare Version Numbers比较版本号
    Leetcode137. Single Number II只出现一次的数字2
    Leetcode129. Sum Root to Leaf Numbers求根到叶子节点数字之和
    Leetcode116. Populating Next Right Pointers in Each Node填充同一层的兄弟节点
    Leetcode114. Flatten Binary Tree to Linked List二叉树展开为链表
    Leetcode113. Path Sum II路径总和2
    C++stl中vector的几种常用构造方法
  • 原文地址:https://www.cnblogs.com/benbenzlj/p/3243558.html
Copyright © 2011-2022 走看看