• Newtonsoft.Json笔记 -JsonConvert自定义序列化与反序列化


    通常的序列化与反序列化中的json结构与c#中的类模型结构是相对应的,我们是否可以在序列化一个对象时候,让我们json的数据结构能按照自己的意愿,而不必与该对象的数据结构一样呢?,比如说,一个对象,只有一个名为"ID"的int类型的属性,值为1,如果序列化该对象,则能得到json:{"ID":1},但我现在希望得到的json的"ID"值是bool类型:{"ID":true}。要满足能够进行自定义序列化与反序列化的要求,我们可以运用json.net中的转换器JsonConverter。
    Newtonsoft提供了StringEnumConverter,它继承自JsonConverter,用于序列化时显示枚举的名称,而不是枚举值

    先来个简单的例子:

            public class Model
            {
                public int ID { get; set; }
            }
    

    定义一个转换器类MyConverter,这个类要继承Newtonsoft.Json命名空间下的一个抽象类JsonConverter,我们先来看下这个抽象类的成员,有两个属性与三个抽象方法:

    在MyConverter中我们要实现这三个抽象方法CanConvert()、ReadJson()、WriteJson(),并用特性[JsonConverter(typeof(MyConverter))]标记在我们要自定义序列化的类Model上就行了
    在序列化Model对象的时候,程序会走到MyConverter下已经实现的WriteJson()方法,反序列化会走到ReadJson()方法,而CanConvert方法是用于判断是否需要自定义序列化或者反序列化的,它的参数objectType对应着特性JsonConverter所标记类的对应Type类型。

    下面是MyConverter类的代码实现:

            [JsonConverter(typeof(MyConverter))]
            public class Model
            {
                public int ID { get; set; }
            } 
    
            public class MyConverter : JsonConverter
            {
                //是否开启自定义反序列化,值为true时,反序列化时会走ReadJson方法,值为false时,不走ReadJson方法,而是默认的反序列化
                public override bool CanRead => true;
                //是否开启自定义序列化,值为true时,序列化时会走WriteJson方法,值为false时,不走WriteJson方法,而是默认的序列化
                public override bool CanWrite => true;
    
                public override bool CanConvert(Type objectType)
                {
                    return typeof(Model) == objectType;
                }
    
                public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
                {
                    var model = new Model();
                    //获取JObject对象,该对象对应着我们要反序列化的json
                    var jobj = serializer.Deserialize<JObject>(reader);
                    //从JObject对象中获取键位ID的值
                    var id = jobj.Value<bool>("ID");
                    //根据id值判断,进行赋值操作
                    if (id)
                    {
                        model.ID = 1;
                    }
                    else
                    {
                        model.ID = 0;
                    }
                    //最终返回的model对象就是json反序列化所得到的Model对象
                    //主要,这里的model对象不一定非得是Model类型,ReadJson方法与WriteJson方法是一样的,可以自由操作反序列生成的对象或者序列化生成的json
                    return model;
                }
    
                public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
                {
                    //new一个JObject对象,JObject可以像操作对象来操作json
                    var jobj = new JObject();
                    //value参数实际上是你要序列化的Model对象,所以此处直接强转
                    var model = value as Model;
                    if (model.ID != 1)
                    {
                        //如果ID值为1,添加一个键位"ID",值为false
                        jobj.Add("ID",false);
                    }
                    else
                    {
                        jobj.Add("ID", true);
                    }
                    //通过ToString()方法把JObject对象转换成json
                    var jsonstr = jobj.ToString();
                    //调用该方法,把json放进去,最终序列化Model对象的json就是jsonstr,由此,我们就能自定义的序列化对象了
                    writer.WriteValue(jsonstr);
                }
            }
    
        class Program
        {
            static void Main(string[] args)
            {
                var model = new Model();
                model.ID = 1;
                var json = JsonConvert.SerializeObject(model);//由于ID值为1,得到json为{"ID":ture}
                var newModel = JsonConvert.DeserializeObject<Model>(json);//序列化得到的newModel对象ID值为1
            }
    
    
        }
    

    以上例子是在类上添加JsonconvertAttribute,下面例子是在属性上添加JsonConvertAttribute:

    public class BoolConvert : JsonConverter
        {
            private string[] arrBString { get; set; }
    
            public BoolConvert()
            {
                arrBString = "是,否".Split(',');
            }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="BooleanString">将bool值转换成的字符串值</param>
            public BoolConvert(string BooleanString)
            {
                if (string.IsNullOrEmpty(BooleanString))
                {
                    throw new ArgumentNullException();
                }
                arrBString = BooleanString.Split(',');
                if (arrBString.Length != 2)
                {
                    throw new ArgumentException("BooleanString格式不符合规定");
                }
            }
    
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                bool isNullable = IsNullableType(objectType);
                Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType;
    
                if (reader.TokenType == JsonToken.Null)
                {
                    if (!IsNullableType(objectType))
                    {
                        throw new Exception(string.Format("不能转换null value to {0}.", objectType));
                    }
    
                    return null;
                }
    
                try
                {
                    if (reader.TokenType == JsonToken.String)
                    {
                        string boolText = reader.Value.ToString();
                        if (boolText.Equals(arrBString[0], StringComparison.OrdinalIgnoreCase))
                        {
                            return true;
                        }
                        else if (boolText.Equals(arrBString[1], StringComparison.OrdinalIgnoreCase))
                        {
                            return false;
                        }
                    }
    
                    if (reader.TokenType == JsonToken.Integer)
                    {
                        //数值
                        return Convert.ToInt32(reader.Value) == 1;
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error converting value {0} to type '{1}'", reader.Value, objectType));
                }
                throw new Exception(string.Format("Unexpected token {0} when parsing enum", reader.TokenType));
            }
    
            /// <summary>
            /// 判断是否为Bool类型
            /// </summary>
            /// <param name="objectType">类型</param>
            /// <returns>为bool类型则可以进行转换</returns>
            public override bool CanConvert(Type objectType)
            {
                return true;
            }
    
    
            public bool IsNullableType(Type t)
            {
                if (t == null)
                {
                    throw new ArgumentNullException("t");
                }
                return (t.BaseType.FullName=="System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>));
            }
    
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                if (value == null)
                {
                    writer.WriteNull();
                    return;
                }
    
                bool bValue = (bool)value;
    
                if (bValue)
                {
                    writer.WriteValue(arrBString[0]);
                }
                else
                {
                    writer.WriteValue(arrBString[1]);
                }
            }
        }
    
        public class Person
        {
            [JsonConverter(typeof(BoolConvert))]
            public bool IsMarry { get; set; }
        }
    

    参考:
    https://www.cnblogs.com/yijiayi/p/10051284.html
    https://blog.csdn.net/MDZZ666/article/details/92838531
    https://blog.csdn.net/stwuyiyu/article/details/51190548

  • 相关阅读:
    wamp+phpzendstudio配置xdebug57%解决办法
    【linux学习问题解决】使用aptget安装软件出现unable to locate package的解决办法
    【linux LAMP平台安装】写在前面(一)
    【linux学习问题解决】更改字符界面大小(转)
    [phpcms二次开发]phpcms生成栏目出错,转到模版页面
    [phpcms二次开发]给url规则添加可用更多自定义可用变量
    [phpcms二次开发]实现获取路径linux与windows路径兼容
    控件注册 利用资源文件将dll、ocx打包进exe文件(转)
    C#串口通信:MSComm控件使用详解
    改善C#程序的建议1:非用ICloneable不可的理由
  • 原文地址:https://www.cnblogs.com/fanfan-90/p/13866912.html
Copyright © 2020-2023  润新知