在JsonConverter中递归调用JsonSerializer

kmbjn2e3  于 2023-08-08  发布在  其他
关注(0)|答案(4)|浏览(140)

我正在写一个JsonConverter来执行一些需要在读/写上完成的转换任务。特别是,我采用了现有的序列化行为,并在写/阅读时添加了一些额外的属性。
JsonConverter内部,我想利用传递的JsonSerializer示例来执行大部分转换功能。然而,当我这样做时,我最终进入了一个递归循环,其中序列化器调用我的转换器,转换器调用序列化器,序列化器调用转换器,等等。
我见过有人使用JsonConvert.SerializeObject,从序列化器示例中传入所有转换器 * 除了 * this。但是,这对我不起作用,因为它绕过了我在序列化器上所做的所有其他定制,例如定制约定解析器和DateTime处理。
有没有一种方法,我可以:
1.使用传递给我的序列化程序示例,但以某种方式排除我的转换器,或者
1.克隆传递给我的序列化器(无需手动构造新序列化器并逐个属性地复制它)并删除我的转换器?

bkhjykvo

bkhjykvo1#

这是一个非常普遍的问题。使用“JsonConvert.SerializeObject”不是一个坏主意。但是,在某些情况下(通常是集合)可以使用的一个技巧是在写入时强制转换为接口,并在阅读时反序列化为简单的派生。
下面是一个简单的转换器,它处理可能已经序列化为一组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> { }
}

字符串

brqmpdu1

brqmpdu12#

**您可以在一次Serialize调用时禁用自己的转换器。**即使转换器是可重入和/或多线程使用的,也可以禁用。

class MyConverter : JsonConverter
{
  [ThreadStatic]
  private static bool Disabled;

  public override bool CanConvert(Type objectType) =>
    Disabled ? (Disabled = false) : the_type_condition;

  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  { ...
    try
    { Disabled = true;
      serializer.Serialize(writer, value); // will not invoke WriteJson recursively
    } finally
    { Disabled = false;
    }
    ...
  }
}

字符串

8oomwypt

8oomwypt3#

您确实可以使用传递给转换器的序列化程序示例,并排除当前转换器。但是,这不是线程安全的(请参阅此答案的注解)

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    serializer.Converters.Remove(this);
    serializer.Serialize(writer, value);
    serializer.Converters.Add(this);
}

字符串

thtygnil

thtygnil4#

抱歉,也许我搞混了。我使用这些方法来序列化我的对象:

using System;
using Newtonsoft.Json;

namespace Utilities
{
    public static class serializer
    {
        public static string SerializeObject(object objectModel) {
            return JsonConvert.SerializeObject(objectModel);
        }
        public static object DeserializeObject<T>(string jsonObject)
        {
            try
            {
                return JsonConvert.DeserializeObject<T>(jsonObject);
            }
            catch (Exception ex) { return null; }
            
        }
    }
}

字符串
我使用了这个代码:

userLoged = (modelUser)serializer.DeserializeObject<modelUser>((string)Session["userLoged"]);


我希望这对你有所帮助。

相关问题