Newtonsoft.Json笔记 -ContractResolver

介绍

ContractResolver能做什么:
为属性添加一些序列化设置
自定义属性名
有选择的序列化属性

CamelCasePropertyNamesContractResolver

Newtonsoft提供了CamelCasePropertyNamesContractResolver,继承自ContractResolver,用于将属性名转成驼峰命名格式

//设置序列化时key为驼峰样式
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

案例

为属性添加一些序列化设置

//为属性添加JsonConverter
public class PropertyResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var jsonProperty = base.CreateProperty(member, memberSerialization);

            if (jsonProperty.PropertyType == typeof(DateTime))
            {
                jsonProperty.Converter = new DateTimeZoneConverter();
                jsonProperty.ItemConverter = new DateTimeZoneConverter();
                //var objType = jsonProperty.DeclaringType;//所在类Type
                //jsonProperty.UnderlyingName;//属性名
                //jsonProperty.PropertyName = "aaa";//修改序列化后的属性名
                //var attributes = jsonProperty.AttributeProvider.GetAttributes(true);//获取属性上所有Attribute
                //jsonProperty.PropertyType = typeof(string);
            }
            return jsonProperty;
        }
    }

自定义属性名

需求:序列化时需要将属性名以下划线分隔并小写的格式显示,如DogName序列化为dog_name
继承DefaultContractResolver,重写ResolvePropertyName方法

    public class UnderlineSplitContractResolver : DefaultContractResolver
    {
        protected override string ResolvePropertyName(string propertyName)
        {
            return CamelCaseToUnderlineSplit(propertyName);
        }

        private string CamelCaseToUnderlineSplit(string name)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < name.Length; i++)
            {
                var ch = name[i];
                if (char.IsUpper(ch) && i > 0)
                {
                    var prev = name[i - 1];
                    if (prev != '_')
                    {
                        if (char.IsUpper(prev))
                        {
                            if (i < name.Length - 1)
                            {
                                var next = name[i + 1];
                                if (char.IsLower(next))
                                {
                                    builder.Append('_');
                                }
                            }
                        }
                        else
                        {
                            builder.Append('_');
                        }
                    }
                }

                builder.Append(char.ToLower(ch));
            }

            return builder.ToString();
        }
    }
    public class Person
    {
        public string Name { get; set; }
        public string DogName { get; set; }
        [JsonProperty("cat_name_1")]
        public string CatName { get; set; }
    }
        static void Main(string[] args)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings
            {
                ContractResolver = new UnderlineSplitContractResolver()
            };
            Person p1 = new Person
            {
                Name = "fan",
                DogName = "ahuang",
                CatName = "nainiu"
            };
            var json = JsonConvert.SerializeObject(p1, settings);
            Console.WriteLine(json);//输出:{"name":"fan","dog_name":"ahuang","cat_name_1":"nainiu"}
            Console.ReadKey();
        }

控制属性是否序列化

根据某些场景,可能A场景输出A,B,C三个属性,B场景输出E,F属性。虽然实际中不一定存在这种需求,但是json.net依然可以支持该特性。
继承默认的DefaultContractResolver类,传入需要输出的属性,retain表示props是需要保留的字段还是要排除的字段

public class LimitPropsContractResolver : DefaultContractResolver
    {
        string[] props = null;

        bool retain;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="props">传入的属性数组</param>
        /// <param name="retain">true:表示props是需要保留的字段  false:表示props是要排除的字段</param>
        public LimitPropsContractResolver(string[] props, bool retain=true)
        {
            //指定要序列化属性的清单
            this.props = props;

            this.retain = retain;
        }

        protected override IList<JsonProperty> CreateProperties(Type type,

        MemberSerialization memberSerialization)
        {
            IList<JsonProperty> list =
            base.CreateProperties(type, memberSerialization);
            //只保留清单有列出的属性
            return list.Where(p => {
                if (retain)
                {
                    return props.Contains(p.PropertyName);
                }
                else
                {
                    return !props.Contains(p.PropertyName);
                }      
            }).ToList();
        }
        public int Age { get; set; }

        [JsonIgnore]
        public bool IsMarry { get; set; }

        public string Sex { get; set; }
  string[] propNames = null;
  if (p.Age > 10)
  {
    propNames = new string[] { "Age", "IsMarry" };
  }
  else
  {
      propNames = new string[] { "Age", "Sex" };
  }
  jsetting.ContractResolver = new LimitPropsContractResolver(propNames);
  Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));

参考:
https://www.it1352.com/1512692.html (ContractResolver与JsonConverter的复杂案例)

posted @ 2020-10-25 11:34  .Neterr  阅读(3790)  评论(0编辑  收藏  举报