How to call JsonConvert.DeserializeObject and disable a JsonConverter applied to a base type via [JsonConverter]?

前端 未结 1 656
借酒劲吻你
借酒劲吻你 2020-11-28 17:11

EDIT: Clarify question:

I have overridden the JsonConverter for a base type (by applying [JsonConverter(typeof(TConverter))] to the superclass), but whe

相关标签:
1条回答
  • 2020-11-28 17:27

    Since you have added [JsonConverter(typeof(JsonProductConverted))] directly to your Product type, you could add a dummy converter to ProductImpl that returns false from CanRead and CanWrite:

    [JsonConverter(typeof(NoConverter))]
    public class ProductImpl : Product
    {
    }
    
    public class NoConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return false;
        }
    
        public override bool CanRead { get { return false; } }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        public override bool CanWrite { get { return false; } }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    This overrides the base class's converter and then falls back on default serialization for both reading and writing

    Sample .Net fiddle.

    Another option would be to use serializer.Populate(). This avoids the call to the converter for the object itself:

    public class JsonProductConverted : JsonTypeInferringConverterBase
    {
        protected override Type InferType(Type objectType, JObject json)
        {
            //var type = GetTypeFromId((int) json["typeId"]); // Construct type from field in 
            return typeof(ProductImpl);
        }
    
        public override bool CanConvert(Type objectType)
        {
            return false;
        }
    }
    
    public abstract class JsonTypeInferringConverterBase : JsonConverter
    {
        public override bool CanWrite { get { return false; } }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    
        protected abstract Type InferType(Type objectType, JObject json);
    
        protected virtual object CreateObject(Type actualType, JsonSerializer serializer, JObject json)
        {
            var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(actualType);
            return contract.DefaultCreator();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var json = JObject.Load(reader);
    
            var actualType = InferType(objectType, json);
    
            // Construct object (or reuse existingValue if compatible)
            if (existingValue == null || !actualType.IsAssignableFrom(existingValue.GetType()))
            {
                existingValue = CreateObject(actualType, serializer, json);
            }
    
            // Populate object.
            using (var subReader = json.CreateReader())
            {
                serializer.Populate(subReader, existingValue);
            }
    
            return existingValue;
        }
    }
    

    Note that the concrete objects must have parameterless constructors for this to work. If not, you can override protected virtual object CreateObject(Type actualType, JsonSerializer serializer, JObject json) and manually invoke a parameterized constructor by deserializing select properties inside the JObject json.

    Sample fiddle #2.

    0 讨论(0)
提交回复
热议问题