如何调用 JsonConvert.DeserializeObject 并禁用通过 [JsonConverter] 应用于基本类型的 JsonConverter? [英] How to call JsonConvert.DeserializeObject and disable a JsonConverter applied to a base type via [JsonConverter]?

查看:20
本文介绍了如何调用 JsonConvert.DeserializeObject 并禁用通过 [JsonConverter] 应用于基本类型的 JsonConverter?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

澄清问题:

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

I have overridden the JsonConverter for a base type (by applying [JsonConverter(typeof(TConverter))] to the superclass), but when deserializing the sub-type directly I want to use STANDARD serialization (i.e. no custom converter) for deserializing my derived object. How do I specify STANDARD serialization for use in the deserialize method, as if I had NOT overridden the JsonConverter?

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

I am using elastic search and can't call JsonConvert.DeserializeObject with my custom implementation of JsonConverter, and have to rely on the attribute for Elastic to use my converter.

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

However, using this converter as attribute seems to affect all sub classes as well, but I just want them to use the standard converter, so that I don't have to implement JsonConverter for each of many implementations.

这是我想要的类/逻辑:

This is my classes/logic as I would like it to look:

    [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 转换器,这会创建一个无限循环.

If I don't supply the default JsonConverter, or similar it will just use the JsonProductConverted converter, which creates an infinite loop.

推荐答案

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

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

示例 .Net fiddle.

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

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;
    }
}

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

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.

示例 小提琴 #2.

这篇关于如何调用 JsonConvert.DeserializeObject 并禁用通过 [JsonConverter] 应用于基本类型的 JsonConverter?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆