在 JsonConverter 中递归调用 JsonSerializer

Recursively call JsonSerializer in a JsonConverter(在 JsonConverter 中递归调用 JsonSerializer)

本文介绍了在 JsonConverter 中递归调用 JsonSerializer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个 JsonConverter 来执行一些我需要在读/写时完成的转换任务.特别是,我采用了现有的序列化行为,并在写入/读取时添加了一些附加属性.

I'm writing a JsonConverter to perform some conversion tasks I need accomplished on read/write. In particular, I'm taking the existing serialization behavior and tacking on some additional properties on write / reading those additional properties on read.

JsonConverter 中,我想利用传递的 JsonSerializer 实例来执行大部分转换功能.但是,当我这样做时,我最终会进入一个递归循环,其中序列化程序调用我的转换器,然后调用序列化程序,然后调用转换器等等.

Inside the JsonConverter, I'd like to make use of the passed JsonSerializer instance to perform the majority of the conversion functionality. However, when I do this, I end up in a recursive loop where the serializer calls into my converter which calls into the serializer which calls into the converter and etc.

我见过人们使用 JsonConvert.SerializeObject,从序列化器实例 except this 传入所有转换器.但是,这对我不起作用,因为它绕过了我在序列化程序上完成的所有其他自定义,例如自定义合同解析器和 DateTime 处理.

I've seen people do things such as use JsonConvert.SerializeObject, passing in all the converters from the serializer instance except this. However, that won't work for me because it bypasses all of the other customization I've done on my serializer, such as custom contract resolver and DateTime handling.

有没有办法:

  1. 使用传递给我的序列化程序实例,但以某种方式排除我的转换器,或者
  2. 克隆传递给我的序列化程序(无需手动构建一个新序列化程序并逐个属性地复制它)并删除我的转换器?

推荐答案

这是一个很常见的问题.使用JsonConvert.SerializeObject"不是一个坏主意.但是,在某些情况下(通常是集合)可以使用的一个技巧是在写入时强制转换为接口,并在读取时反序列化为简单的派生.

This is a very common problem. Using "JsonConvert.SerializeObject" isn't a bad idea. However, one trick that can be used in some circumstances (typically collections) is to cast to the interface when writing and deserialize to a simple derivative when reading.

下面是一个简单的转换器,它处理可能被序列化为一组 KVP 而不是看起来像一个对象的字典(在这里显示我的年龄 :))

Below is a simple converter that deals with dictionaries that might have been serialized as a set of KVPs rather than looking like an object (showing my age here :) )

注意WriteJson"转换为 IDictionary

K,V> 和ReadJson"使用DummyDictionary".您最终得到了正确的结果,但使用了传递的序列化程序而不会导致递归.

Note "WriteJson" casts to IDictionary< K,V> and "ReadJson" uses "DummyDictionary". You end up with the right thing but uses the passed serializer without causing recursion.

/// <summary>
/// Converts a <see cref="KeyValuePair{TKey,TValue}"/> to and from JSON.
/// </summary>
public class DictionaryAsKVPConverter<TKey, TValue> : JsonConverter
{
    /// <summary>
    /// Determines whether this instance can convert the specified object type.
    /// </summary>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>
    ///     <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type objectType)
    {
        if (!objectType.IsValueType && objectType.IsGenericType)
            return (objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>));

        return false;
    }

    /// <summary>
    /// Writes the JSON representation of the object.
    /// </summary>
    /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    /// <param name="value">The value.</param>
    /// <param name="serializer">The calling serializer.</param>
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var dictionary = value as IDictionary<TKey, TValue>;
        serializer.Serialize(writer, dictionary);
    }

    /// <summary>
    /// Reads the JSON representation of the object.
    /// </summary>
    /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
    /// <param name="objectType">Type of the object.</param>
    /// <param name="existingValue">The existing value of object being read.</param>
    /// <param name="serializer">The calling serializer.</param>
    /// <returns>The object value.</returns>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Dictionary<TKey, TValue> dictionary;

        if (reader.TokenType == JsonToken.StartArray)
        {
            dictionary = new Dictionary<TKey, TValue>();
            reader.Read();
            while (reader.TokenType == JsonToken.StartObject)
            {
                var kvp = serializer.Deserialize<KeyValuePair<TKey, TValue>>(reader);
                dictionary[kvp.Key] = kvp.Value;
                reader.Read();
            }
        }
        else if (reader.TokenType == JsonToken.StartObject)
            // Use DummyDictionary to fool JsonSerializer into not using this converter recursively
            dictionary = serializer.Deserialize<DummyDictionary>(reader);
        else
            dictionary = new Dictionary<TKey, TValue>();

        return dictionary;
    }

    /// <summary>
    /// Dummy to fool JsonSerializer into not using this converter recursively
    /// </summary>
    private class DummyDictionary : Dictionary<TKey, TValue> { }
}

这篇关于在 JsonConverter 中递归调用 JsonSerializer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:在 JsonConverter 中递归调用 JsonSerializer

基础教程推荐