Newtonsoft.Json筆記 -JsonConvert自定義序列化與反序列化


通常的序列化與反序列化中的json結構與c#中的類模型結構是相對應的,我們是否可以在序列化一個對象時候,讓我們json的數據結構能按照自己的意願,而不必與該對象的數據結構一樣呢?,比如說,一個對象,只有一個名為"ID"的int類型的屬性,值為1,如果序列化該對象,則能得到json:{"ID":1},但我現在希望得到的json的"ID"值是bool類型:{"ID":true}。要滿足能夠進行自定義序列化與反序列化的要求,我們可以運用json.net中的轉換器JsonConverter。

JsonConverter

Newtonsoft.Json命名空間下的一個抽象類JsonConverter,我們先來看下這個抽象類的成員:

    public abstract class JsonConverter
    {
        public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

        public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

        public abstract bool CanConvert(Type objectType);

        public virtual bool CanRead => true;

        public virtual bool CanWrite => true;
    }

JSON.NET提供的JsonConverter

XmlNodeConverter、UnixDateTimeConverter、、IsoDateTimeConverter、ExpandoObjectConverter、EntityKeyMemberConverter、DiscriminatedUnionConverter、DataTableConverter、DataSetConverter、BsonObjectIdConverter、BinaryConverter
VersionConverter:序列化System.Version類型時使用
RegexConverter:序列化Regex類型時使用

 private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer)
        {
            DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;

            writer.WriteStartObject();
            writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName);
            writer.WriteValue(regex.ToString());
            writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(OptionsName) : OptionsName);
            serializer.Serialize(writer, regex.Options);
            writer.WriteEndObject();
        }

KeyValuePairConverter:序列化KeyValuePair<,>類型時使用
JavaScriptDateTimeConverter:將時間類型的屬性序列化為Javascript類型的時間格式

JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter();
            DateTime d = new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc);
            string result = JsonConvert.SerializeObject(d, converter);
            Assert.AreEqual("new Date(976918263055)", result);

StringEnumConverter:用於序列化時顯示枚舉的名稱,而不是枚舉值

如何使用

定義一個轉換器類MyConverter,這個類要實現這三個抽象方法CanConvert()、ReadJson()、WriteJson()
在序列化Model對象的時候,程序會走到MyConverter下已經實現的WriteJson()方法,反序列化會走到ReadJson()方法,而CanConvert方法是用於判斷是否需要自定義序列化或者反序列化的,它的參數objectType對應着特性JsonConverter所標記類的對應Type類型。

三種方式設置Converter

  • 在我們要自定義序列化的類或屬性上標記[JsonConverter(typeof(MyConverter))]
  • 在序列化、反序列化時使用
string j = JsonConvert.SerializeObject(s, new JsonSerializerSettings
            {
                Converters = { new JavaScriptDateTimeConverter() }
            });
  • 全局設置
services.AddNewtonsoft(.....);

案例1

先來個簡單的例子:

        [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
        }


    }

案例2

以上例子是在類上添加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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM