JsonSerializer反序列化

string strjson = "{ \"Id\":1,\"Name\":\"\u5F20\u73CA\",\"BirthDay\":\"2020-07-27T00:00:00+08:00\"}";
JsonSerializer.Deserialize<Student>(strjson);

当我们用静态类 JsonSerializer 反序列化一个字符串strjson 时,如果strjson 不是一个有效的Json 字符串,就会报错,

 所以我们封装一个方法,来处理JsonException发生的情况

1:第一种方法最简单

    public static class JsonSerializerExtensions
    {
        public static TValue Deserialize<TValue>(string json, JsonSerializerOptions options = null) where TValue : new()
        {
            try
            {
                return JsonSerializer.Deserialize<TValue>(json, options);
            }
            catch (JsonException)
            {
                return new TValue();
            }
        }
    }

直接用try/catch包起来。

2:只有json字符串是有效的,我们就可以转化成一个动态对象dynamic,直接上代码

public class DynamicJsonConverter : JsonConverter<dynamic>
    {
        public override dynamic Read(ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options)
        {

            if (reader.TokenType == JsonTokenType.True)
            {
                return true;
            }

            if (reader.TokenType == JsonTokenType.False)
            {
                return false;
            }

            if (reader.TokenType == JsonTokenType.Number)
            {
                if (reader.TryGetInt64(out long l))
                {
                    return l;
                }

                return reader.GetDouble();
            }

            if (reader.TokenType == JsonTokenType.String)
            {
                if (reader.TryGetDateTime(out DateTime datetime))
                {
                    return datetime;
                }

                return reader.GetString();
            }

            if (reader.TokenType == JsonTokenType.StartObject)
            {
                using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
                return ReadObject(documentV.RootElement);
            }
            // Use JsonElement as fallback.
            // Newtonsoft uses JArray or JObject.
            JsonDocument document = JsonDocument.ParseValue(ref reader);
            return document.RootElement.Clone();
        }

        private object ReadObject(JsonElement jsonElement)
        {
            IDictionary<string, object> expandoObject = new ExpandoObject();
            foreach (var obj in jsonElement.EnumerateObject())
            {
                var k = obj.Name;
                var value = ReadValue(obj.Value);
                expandoObject[k] = value;
            }
            return expandoObject;
        }
        private object? ReadValue(JsonElement jsonElement)
        {
            object? result = null;
            switch (jsonElement.ValueKind)
            {
                case JsonValueKind.Object:
                    result = ReadObject(jsonElement);
                    break;
                case JsonValueKind.Array:
                    result = ReadList(jsonElement);
                    break;
                case JsonValueKind.String:
                    //TODO: Missing Datetime&Bytes Convert
                    result = jsonElement.GetString();
                    break;
                case JsonValueKind.Number:
                    //TODO: more num type
                    result = 0;
                    if (jsonElement.TryGetInt64(out long l))
                    {
                        result = l;
                    }
                    break;
                case JsonValueKind.True:
                    result = true;
                    break;
                case JsonValueKind.False:
                    result = false;
                    break;
                case JsonValueKind.Undefined:
                case JsonValueKind.Null:
                    result = null;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            return result;
        }

        private object? ReadList(JsonElement jsonElement)
        {
            IList<object?> list = new List<object?>();
            foreach (var item in jsonElement.EnumerateArray())
            {
                list.Add(ReadValue(item));
            }
            return list.Count == 0 ? null : list;
        }
        public override void Write(Utf8JsonWriter writer,
            object value,
            JsonSerializerOptions options)
        {
            // writer.WriteStringValue(value.ToString());
        }
    }

这只是帮助类,要怎么用呐?

                var serializerOptions = new JsonSerializerOptions
                {
                    Converters = { new DynamicJsonConverter() }
                };

                var str = "{\"OK\":\"200\"}";

                var res = JsonSerializer.Deserialize<dynamic>(str, serializerOptions);

这种情况有一个小bug,就是当json字符串无效时会直接报错。

3:写一个校验方法,判断json字符串和给定的类型是否匹配

public class SerializerExtend
    {
        public static bool Fun(Type type, string jsonStr)
        {
            JObject jObject;
            try
            {
                jObject = JObject.Parse(jsonStr);
            }
            catch (JsonReaderException)
            {
                return false;
            }

            var propertys = type.GetProperties();

            
            foreach (JProperty child in jObject.Children())
            {
                var oneBool = false;

                foreach (var property in propertys)
                {
                    //先判断名称是否一样
                    if (string.Equals(property.Name, child.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        //再判断类型是否一样
                        if (child.HasValues)
                        {
                            if (child.Type == JTokenType.Object)
                            {
                                var childBool = Fun(property.PropertyType, child.Value.ToString());
                                if (childBool == false)
                                    return false;
                            }
                            else
                            {
                                if (dic[Type.GetTypeCode(property.PropertyType)] == child.Value.Type)
                                {
                                    oneBool = true;
                                    break;
                                }
                            }
                        }
                    }
                }

                if (oneBool == false) //没有匹配上
                    return false;
            }

            return true;
        }

        private static Dictionary<TypeCode, JTokenType> dic
        {
            get
            {
                if (_dic == null)
                    DicInit();

                return _dic;
            }
        }
        private static Dictionary<TypeCode, JTokenType> _dic = null;
        private static void DicInit()
        {
            _dic = new Dictionary<TypeCode, JTokenType>();
            dic.Add(TypeCode.Empty, JTokenType.String);
            dic.Add(TypeCode.Object, JTokenType.Object);
            dic.Add(TypeCode.DBNull, JTokenType.Null);
            dic.Add(TypeCode.Boolean, JTokenType.Boolean);
            dic.Add(TypeCode.Char, JTokenType.String);
            dic.Add(TypeCode.SByte, JTokenType.Integer);
            dic.Add(TypeCode.Byte, JTokenType.Integer);
            dic.Add(TypeCode.Int16, JTokenType.Integer);
            dic.Add(TypeCode.UInt16, JTokenType.Integer);
            dic.Add(TypeCode.Int32, JTokenType.Integer);
            dic.Add(TypeCode.UInt32, JTokenType.Integer);
            dic.Add(TypeCode.Int64, JTokenType.Integer);
            dic.Add(TypeCode.UInt64, JTokenType.Integer);
            dic.Add(TypeCode.Single, JTokenType.Float);
            dic.Add(TypeCode.Double, JTokenType.Float);
            dic.Add(TypeCode.Decimal, JTokenType.Float);
            dic.Add(TypeCode.DateTime, JTokenType.Date);
            dic.Add(TypeCode.String, JTokenType.String);
        }

    }

使用方法

      string strjson = "{ \"Id\":1,\"Name\":\"\u5F20\u73CA\",\"BirthDay\":\"2020-07-27T00:00:00+08:00\"}";  
                var jsun = SerializerExtend.Fun(typeof(Student), strjson);

这个方法,本人只是做了简单的认证,可能还有一些要完善的地方,如有发现,请留言。

此方法和第2种方法一样。就是当json字符串无效时会直接报错。

猜你喜欢

转载自www.cnblogs.com/xiaoZhang521/p/13387985.html