c# - 在 JsonConverter 中递归调用 JsonSerializer

标签 c# .net json serialization json.net

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

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

我见过人们做一些事情,例如使用 JsonConvert.SerializeObject,从序列化程序实例 except this 传递所有转换器。但是,这对我不起作用,因为它绕过了我在序列化程序上完成的所有其他自定义,例如自定义契约(Contract)解析器和 DateTime 处理。

有什么办法可以:

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

最佳答案

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

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

注意“WriteJson”强制转换为 IDictionary< K,V>,“ReadJson”使用“DummyDictionary”。您最终得到了正确的结果,但使用了传递的序列化程序而不会导致递归。

/// <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> { }
}

关于c# - 在 JsonConverter 中递归调用 JsonSerializer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16085805/

相关文章:

c# - 每种语言的 sitecore 中最受欢迎的项目。

javascript - 没有每个函数的 JSON 解码

jquery - 如何在周 View 和日 View 中调整 jQuery Full Calendar 中事件的宽度和位置

c# - TPL 数据流 block 消耗所有可用内存

.net - 单操作系统特定 DLL

javascript - EmberJS 使用 View 处理 DOM 事件

c# - 如何在 C# 电子邮件中将正文格式设置为 HTML

c# - 为操作设置超时

c# - 如何在 MonoTouch 中代理 UIKit 委托(delegate)?

c# - 获取由 Windows 快捷方式配置的正确窗口样式