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

前端 未结 9 1828
星月不相逢
星月不相逢 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 05:44

    This is an expansion to totem's answer. It does basically the same thing but the property matching is based on the serialized json object, not reflect the .net object. This is important if you're using [JsonProperty], using the CamelCasePropertyNamesContractResolver, or doing anything else that will cause the json to not match the .net object.

    Usage is simple:

    [KnownType(typeof(B))]
    public class A
    {
       public string Name { get; set; }
    }
    
    public class B : A
    {
       public string LastName { get; set; }
    }
    

    Converter code:

    /// 
    /// Use KnownType Attribute to match a divierd class based on the class given to the serilaizer
    /// Selected class will be the first class to match all properties in the json object.
    /// 
    public class KnownTypeConverter : JsonConverter {
        public override bool CanConvert( Type objectType ) {
            return System.Attribute.GetCustomAttributes( objectType ).Any( v => v is KnownTypeAttribute );
        }
    
        public override bool CanWrite {
            get { return false; }
        }
    
        public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ) {
            // Load JObject from stream
            JObject jObject = JObject.Load( reader );
    
            // Create target object based on JObject
            System.Attribute[ ] attrs = System.Attribute.GetCustomAttributes( objectType );  // Reflection. 
    
            // check known types for a match. 
            foreach( var attr in attrs.OfType( ) ) {
                object target = Activator.CreateInstance( attr.Type );
    
                JObject jTest;
                using( var writer = new StringWriter( ) ) {
                    using( var jsonWriter = new JsonTextWriter( writer ) ) {
                        serializer.Serialize( jsonWriter, target );
                        string json = writer.ToString( );
                        jTest = JObject.Parse( json );
                    }
                }
    
                var jO = this.GetKeys( jObject ).Select( k => k.Key ).ToList( );
                var jT = this.GetKeys( jTest ).Select( k => k.Key ).ToList( );
    
                if( jO.Count == jT.Count && jO.Intersect( jT ).Count( ) == jO.Count ) {
                    serializer.Populate( jObject.CreateReader( ), target );
                    return target;
                }
            }
    
            throw new SerializationException( string.Format( "Could not convert base class {0}", objectType ) );
        }
    
        public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) {
            throw new NotImplementedException( );
        }
    
        private IEnumerable> GetKeys( JObject obj ) {
            var list = new List>( );
            foreach( var t in obj ) {
                list.Add( t );
            }
            return list;
        }
    }
    

提交回复
热议问题