如何调用 JsonConvert.DeserializeObject 并禁用通过 [JsonConverter] 应用于基本类型的 JsonConverter?

Posted

技术标签:

【中文标题】如何调用 JsonConvert.DeserializeObject 并禁用通过 [JsonConverter] 应用于基本类型的 JsonConverter?【英文标题】:How to call JsonConvert.DeserializeObject and disable a JsonConverter applied to a base type via [JsonConverter]? 【发布时间】:2018-01-14 18:32:15 【问题描述】:

编辑:澄清问题:

我已经为基类型覆盖了 JsonConverter(通过将 [JsonConverter(typeof(TConverter))] 应用于超类),但是当直接反序列化子类型时,我想使用 STANDARD 序列化(即没有自定义转换器)来反序列化我的派生对象。如何在反序列化方法中指定 STANDARD 序列化,就好像我没有覆盖 JsonConverter 一样?

我正在使用弹性搜索,无法使用我的自定义 JsonConverter 实现调用 JsonConvert.DeserializeObject,并且必须依赖 Elastic 的属性才能使用我的转换器。

但是,使用这个转换器作为属性似乎也会影响所有子类,但我只是希望它们使用标准转换器,这样我就不必为许多实现中的每一个都实现 JsonConverter。

这是我想要的类/逻辑:

    [Route("test")]
    [HttpPost]
    public HttpResponseMessage Test([FromBody] JToken json)
    
        var res = json.ToObject<Product>(); // I want an object of ProductImpl type here
        return Request.CreateResponse(res); 
    

    [JsonConverter(typeof(JsonProductConverted))]
    public abstract class Product
    
    

    public class ProductImpl : Product
    
    

    public class JsonProductConverted : JsonConverter
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        
            throw new NotImplementedException();
        

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        
            JObject json = JObject.Load(reader);
            //var type = GetTypeFromId((int) json["typeId"]); // Construct type from field in 
            var type = typeof(ProductImpl);
            // var res = JsonConvert.DeserializeObject(json.ToString(), type, DEFAULT_JSONCONVERTER_HERE);
            var res = DeserializeToObjectWithStandardJsonConverter(json, type);
            return res;
        

        public override bool CanConvert(Type objectType)
        
            return false;
        
    

如果我不提供默认的 JsonConverter 或类似的,它将只使用 JsonProductConverted 转换器,这会创建一个无限循环。

【问题讨论】:

请试着提出一个明确的问题,很难得到你想要的。 【参考方案1】:

由于您已将[JsonConverter(typeof(JsonProductConverted))] 直接添加到您的Product 类型,您可以将一个虚拟转换器添加到ProductImpl,它从CanReadCanWrite 返回false

[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();
    

这会覆盖基类的转换器,然后回退到读取和写入的默认序列化

示例.Net fiddle。

另一种选择是使用serializer.Populate()。这避免了为对象本身调用转换器:

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;
    

请注意,具体对象必须具有无参数的构造函数才能使其工作。如果没有,您可以覆盖 protected virtual object CreateObject(Type actualType, JsonSerializer serializer, JObject json) 并通过反序列化 JObject json 中的选择属性来手动调用参数化构造函数。

示例fiddle #2。

【讨论】:

这工作 100%。允许在 Elastic Search 中保存抽象类,然后非常容易地将它们反序列化为真实对象,即使对于具有大量实现的抽象对象,这也变得非常简单。非常感谢。 这太棒了,但我需要在我的具体类中添加一个私有 json 构造函数,以使它们正确反序列化。如果能得到一个完整的解释(或链接)那么合同是什么方面是关于因为我现有的知识没有扩展到那个,我永远不会解决这个问题

以上是关于如何调用 JsonConvert.DeserializeObject 并禁用通过 [JsonConverter] 应用于基本类型的 JsonConverter?的主要内容,如果未能解决你的问题,请参考以下文章

Excel中的VBA如何调用Java呀?

java如何调用webservice接口?

java如何调用接口方式

如何使用CXF调用webservice接口

Oracle如何创建存储过程和如何调用存储过程

如何调用别人提供的webservice接口