【问题标题】:Custom JsonConverter gets reader with TokenType "EndObject" when it shouldn't be自定义 JsonConverter 在不应该使用 TokenType“EndObject”时获取阅读器
【发布时间】:2015-08-26 21:53:10
【问题描述】:

我有一个带有 JSON 对象数组的流,它们有两种不同的格式,但包含相同类型的数据,我想将这两种格式反序列化为相同的类型,因此我的视图不需要自定义逻辑两种格式的数据。目前我正在使用自定义 JsonConverter 处理此问题。

这是我的模型:

[JsonObject]
[JsonConverter(typeof(MyCommonObjectJsonConverter))]
public class MyCommonObject {
    // some common fields, e.g.
    public String Id { get; set; }
    public string Text { get; set; }
}

这是我的自定义 JsonConverter:

public class MyCommonObjectJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // don't need to worry about serialization in this case, only
        // reading data
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jObject = JObject.Load(reader);

        MyCustomObject result;
        if (IsFormatOne(jObject))
        {
            // the structure of the object matches the first format,
            // so just deserialize it directly using the serializer
            result = serializer.Deserialize<MyCustomObject>(reader);
        }
        else if (IsFormatTwo(jObject))
        {
            result = new MyCustomObject();

            // initialize values from the JObject
            // ... 
        }
        else
        {
            throw new InvalidOperationException("Unknown format, cannot deserialize");
        }

        return result;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(MyCustomObject).IsAssignableFrom(objectType);
    }

    // Definitions of IsFormatOne and IsFormatTwo
    // ...
}

但是,当我反序列化第一种格式的对象时,我收到一条错误消息,指出它无法加载 JObject,因为 JsonReader 的 TokenType 为“EndToken”。我不确定为什么会这样,我加载的数据格式正确。关于我应该注意什么有什么建议吗?

【问题讨论】:

    标签: c# .net serialization json.net


    【解决方案1】:

    您希望在阅读 MyCommonObject 时退回到默认反序列化,但是:

    • 如您所见,对JObject.Load(reader) 的调用已经使读者超越了该对象,并且
    • 调用serializer.Deserialize&lt;MyCustomObject&gt;(reader) 无论如何都会导致无限递归。

    在这种情况下避免ReadJson() 中不必要的递归的惯用方法是手动分配结果,然后调用serializer.Populate(jObject.CreateReader(), result)。即:

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
    
            JObject jObject = JObject.Load(reader);
    
            MyCommonObject result;
            if (IsFormatOne(jObject))
            {
                result = (existingValue as MyCommonObject ?? (MyCommonObject)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator()); // Reuse existingValue if present
                // the structure of the object matches the first format,
                // so just deserialize it directly using the serializer
                using (var subReader = jObject.CreateReader())
                    serializer.Populate(subReader, result);
            }
            else if (IsFormatTwo(jObject))
            {
                result = (existingValue as MyCommonObject ?? (MyCommonObject)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
    
                // initialize values from the JObject
                // ... 
            }
            else
            {
                throw new InvalidOperationException("Unknown format, cannot deserialize");
            }
    
            return result;
        }
    

    【讨论】:

      【解决方案2】:

      在写这篇文章时想通了,调用serializer.Deserialize&lt;MyCustomObject&gt;(reader) 再次递归到我的转换器中,此时阅读器将到达一个结束令牌,从被加载到 JObject 中,使 TokenType 等于 EndToken。我应该更仔细地检查堆栈跟踪。现在我将为这两种格式编写自定义初始化逻辑,使我的模型类与格式无关。

      【讨论】:

      • 作为后续,有没有什么方法可以不使用模型的自定义转换器,将JSON对象转换成模型呢?即只使用默认的
      • 当您想退回到标准行为时,避免ReadJson() 中递归的习惯方法是自己分配对象,然后调用serializer.Populate(jObject.CreateReader(), result)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-07
      相关资源
      最近更新 更多