How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

前端 未结 9 1830
星月不相逢
星月不相逢 2020-11-21 05:07

I am trying to extend the JSON.net example given here http://james.newtonking.com/projects/json/help/CustomCreationConverter.html

I have another sub class deriving

9条回答
  •  醉梦人生
    2020-11-21 06:10

    A lot of the times the implementation will exist in the same namespace as the interface. So, I came up with this:

        public class InterfaceConverter : JsonConverter
        {
        public override bool CanWrite => false;
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var token = JToken.ReadFrom(reader);
            var typeVariable = this.GetTypeVariable(token);
            if (TypeExtensions.TryParse(typeVariable, out var implimentation))
            { }
            else if (!typeof(IEnumerable).IsAssignableFrom(objectType))
            {
                implimentation = this.GetImplimentedType(objectType);
            }
            else
            {
                var genericArgumentTypes = objectType.GetGenericArguments();
                var innerType = genericArgumentTypes.FirstOrDefault();
                if (innerType == null)
                {
                    implimentation = typeof(IEnumerable);
                }
                else
                {
                    Type genericType = null;
                    if (token.HasAny())
                    {
                        var firstItem = token[0];
                        var genericTypeVariable = this.GetTypeVariable(firstItem);
                        TypeExtensions.TryParse(genericTypeVariable, out genericType);
                    }
    
                    genericType = genericType ?? this.GetImplimentedType(innerType);
                    implimentation = typeof(IEnumerable<>);
                    implimentation = implimentation.MakeGenericType(genericType);
                }
            }
    
            return JsonConvert.DeserializeObject(token.ToString(), implimentation);
        }
    
        public override bool CanConvert(Type objectType)
        {
            return !typeof(IEnumerable).IsAssignableFrom(objectType) && objectType.IsInterface || typeof(IEnumerable).IsAssignableFrom(objectType) && objectType.GetGenericArguments().Any(t => t.IsInterface);
        }
    
        protected Type GetImplimentedType(Type interfaceType)
        {
            if (!interfaceType.IsInterface)
            {
                return interfaceType;
            }
    
            var implimentationQualifiedName = interfaceType.AssemblyQualifiedName?.Replace(interfaceType.Name, interfaceType.Name.Substring(1));
            return implimentationQualifiedName == null ? interfaceType : Type.GetType(implimentationQualifiedName) ?? interfaceType;
        }
    
        protected string GetTypeVariable(JToken token)
        {
            if (!token.HasAny())
            {
                return null;
            }
    
            return token.Type != JTokenType.Object ? null : token.Value("$type");
        }
    }
    

    Therefore, you can include this globally like so:

    public static JsonSerializerSettings StandardSerializerSettings => new JsonSerializerSettings
        {
            Converters = new List
            {
                new InterfaceConverter()
            }
        };
    

提交回复
热议问题