zoukankan      html  css  js  c++  java
  • 三:C#对象转换Json时的一些高级(特殊)设置;

    导航目录:

       Newtonsoft.Json 概述

      一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;

        二:C#对象、集合、DataTable与Json内容互转示例;

      三:C#对象转换Json时的一些高级(特殊)设置;

       前面两篇分别介绍了C#转换JSON时一些常规的用法,以前我也是,只用到了前面这些比较常用的方法,没想到在转换时还有那么多特殊的设置,

    今天这篇内容就来讲一下一些特殊的设置,比如,转换时过滤掉个别属性、重命名字段名称、枚举字段的处理、私有变量的转换等;

      好了,开始今天的正题:

    序列化时忽略特定的属性字段

    需求分析:有时候在前后台或者APP直接进行数据交互的时候,不需要全部的属性内容,举个栗子,比如,只想知道用户的名字叫啥,如果把用户的年龄、

    性别,爱好都返回,中间的传输过程就会占用宽带,而且,其它的字段也不需要,也浪费了转换的性能。SO,还是前面文章中的对象类,咱们改进下,比

    如,现在我们只想要这个用户的名字叫啥,代码怎么改呢?

    有两种方式可以实现,方式1:比如你去饭店,告诉老板我要这个菜,这个菜,还有那个菜。

      [JsonObject(MemberSerialization.OptIn)]   //这个标签定义了你的选菜方式,只选我要的
        public class PeopleInfo
        {
    
            [JsonProperty]   //这个标签标记了这个是你要选择的菜品
    
            public string Name { get; set; }
    
            [JsonProperty]   //这个标签标记了这个是你要选择的菜品
    
            public int Age { get; set; }
    
            public DateTime Birthday { get; set; }
    
            public EnumGender Gender { get; set; }
    
            public List<string> Hobby
    
            { get; set; }
    
    }
    

    【OptIn情况下,默认是将所有的属性都定义成了不要,如果这个属性需要转换成Json,需要标记JsonProperty】

    转换后的结果:

    方式2:就是你去饭店,告诉老板我不要这个菜,不要这个菜。

    [JsonObject(MemberSerialization.OptOut)]   //这个标签定义了你的选菜方式,排除我不要的
        public class PeopleInfo
        {
            public string Name { get; set; }
    
            [JsonIgnore]  //这个标签标记了这个不是要想要的菜品
            public int Age { get; set; }
            [JsonIgnore]   //这个标签标记了这个不是要想要的菜品
            public DateTime Birthday { get; set; }
            public EnumGender Gender { get; set; }
            public List<string> Hobby
            { get; set; }
    }
    

    【OptOut情况下,默认是将所有的属性都定义成了要转换Json,如果这个属性不需要转换成Json,需要标记JsonIgnore】

    序列化时更改(重命名)属性名称;

    需求分析:有时候实体类中定义的属性名称可能不是想要的名称,但是又不能更改实体类中属性的名称,这个时候就可以自定义序列化字段名称。

    这就好比,饭店里面的一道菜菜单叫蚂蚁上树,实际上就是一道粉丝炒肉末,蚂蚁上树就是重命名的属性名称,粉丝炒肉末才是它的实体类名称;

    还是复用前面的代码,稍微修改下:

    public class PeopleInfo
        {
            [JsonProperty(PropertyName = "名称")] //写法1
            public string Name { get; set; }             
    [JsonProperty("年龄")]   //写法2
            public int Age { get; set; }
            public DateTime Birthday { get; set; }
            public EnumGender Gender { get; set; }
            public List<string> Hobby
            { get; set; }
        }
    

    转换后的结果:

     

     

    序列化时将非公共变量(private)转换为Json;

    分析:一般情况下,在进行Json转换的时候,只会对public 成员进行Json转换,默认情况下,私有成员是不转换的。

    只需要在属性上标记[JsonProperty]就可以了。如下图:

    序列化时忽略空值的属性字段;

    分析:上上面的例子中,Name字段为Null值,假如实际前后端数据交互中,Null值的数据返回岂不是很没有意义?为此,我们

    可以设置下,如果值为Null值时,就不进行序列化转换。

    方式1:在属性成员中指定NullValueHandling方式。

    【NullValueHandling:这是每个枚举值,Ignore忽略空值,Include包含空值】

    方式2:通过上面的示例,我们可以发现,可以对单个属性进行设置,如果一个实体类有20个属性成员,30个属性成员,然后,

    一个一个去设置岂不是很二,有没有更高效的方式呢?答案是当然有的啦,看下面,这个方式就不需要在单独对每一个属性进行设置了。

    代码:

    private void btnJsonDemo_Click(object sender, EventArgs e)
            {
                PeopleInfo p = new PeopleInfo();
                //p.Name = "李家村的二狗子";   //没有对Name属性赋值,Name值为Null值
                p.Age = 30;
                p.Birthday = DateTime.Now;
                p.Gender = EnumGender.male;
                p.Hobby = new List<string> { "写Bug", "钓鱼", "看新闻联播" };
    
                JsonSerializerSettings setting = new JsonSerializerSettings();
                setting.NullValueHandling = NullValueHandling.Ignore;   //设置全局的Null值处理,JsonSerializerSettings竟然没有构造函数,一点都不OOP
                string json = JsonConvert.SerializeObject(p, setting);
                this.txtResult.Text = json;
            }
    

      

    转换结果如下图:

    序列化时枚举值的处理;

    分析:在上面的例子中,所转换的Gender都是int类型的,假如,我们在转换Json时需要转换成对应的字符怎么操作呢?

    代码:[JsonConverter(typeof(StringEnumConverter))]

    根据条件来设置属性是否序列化;

    Json.NET能够通过在类上放置ShouldSerialize方法来有条件地序列化属性,要有条件地序列化属性,需要在对象类中增加一个

    与该属性同名的布尔值的方法,然后使用ShouldSerialize作为方法名称的前缀,比如你要设置属性字段Name根据条件来动态决

    定是否序列化,则方法名一定要写成ShouldSerializeName()。方法的返回值必须是bool类型,如果返回true,表示这个属性可以

    序列化,返回false表示不被序列化。

    还用以前的PeopleInfo 类,稍微改进下:

    public class PeopleInfo
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public DateTime Birthday { get; set; }
            public EnumGender Gender { get; set; }
    
            public List<string> Hobby { get; set; }
    
            //注意方法名称以及方法类型
            public bool ShouldSerializeName()
            {
                if (this.Name == "李四")  //如果名称是李四,则Name属性不序列化
                    return false;
                return true;
            }
    }
    

      

    调用方法:

    List<PeopleInfo> list = new List<PeopleInfo>();
                PeopleInfo p = new PeopleInfo();
                p.Name = "李二狗";
                p.Age = 30;
                p.Birthday = DateTime.Now;
                p.Gender = EnumGender.male;
                p.Hobby = new List<string> { "写Bug", "钓鱼", "看新闻联播" };
                list.Add(p);
    
                PeopleInfo p1 = new PeopleInfo();
                p1.Name = "李四";
                p1.Age = 30;
                p1.Birthday = DateTime.Now;
                p1.Gender = EnumGender.male;
                p1.Hobby = new List<string> { "工作" };
                list.Add(p1);
    
                string json = JsonConvert.SerializeObject(list);
                this.txtResult.Text = json;
    

      转换结果如下图:

    问题升级:如果需要两个或者多个属性都可以根据条件来序列化?难道要写很多个方法?

    根据条件来设置多个属性是否序列化;

    针对上面的问题,如果有多个属性需要根据条件来序列化怎么办?我们可以新增一个方法,如下:

    public class LimitPropsContractResolver : DefaultContractResolver
        {
            string[] Propertys = null;
            bool IsSerialize;
            public LimitPropsContractResolver(string[] props, bool retain = true)
            {
                this.Propertys = props;
                this.IsSerialize = retain;
            }
            protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
            {
                IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
                return list.Where(p =>
                {
                    if (IsSerialize)
                    {
                        return Propertys.Contains(p.PropertyName);
                    }
                    else
                    {
                        return !Propertys.Contains(p.PropertyName);
                    }
                }).ToList();
            }
    }
    

      调用的时候,只需要把字段名称传入string数组中就可以,bool值表示是否需要转换此字段;调用方法如下:

    JsonSerializerSettings settings = new JsonSerializerSettings();
                settings.ContractResolver = new LimitPropsContractResolver(new string[] { "Gender", "Hobby" }, false);
                string json = JsonConvert.SerializeObject(list, settings);
    

      

    参考:

    官方:https://github.com/JamesNK/Newtonsoft.Json

    官方文档:https://www.newtonsoft.com/json/help/html/Introduction.htm

    https://www.cnblogs.com/leonsky/p/3300511.html

    http://www.cnblogs.com/yanweidie/p/4605212.html#_label2

    感谢官方以及部分原文作者。

  • 相关阅读:
    Android UI之LinearLayout详解
    在zxing开源项目里,camera.setDisplayOrientation(90)出现错误
    DjangoORM获取值的不同类型
    DjangoORM操作数据库
    Django的URL写法
    创建django项目的基础命令&知识(一)
    python读取EXCEL的某一列,并保存到txt文本中
    后台管理页面基础布局HTML+CSS
    使用yaml格式进行接口测试报错
    常见的sql语句练习
  • 原文地址:https://www.cnblogs.com/Rawls/p/10338439.html
Copyright © 2011-2022 走看看