我该如何使用JSON.NET处理有时是对象,有时是对象数组的值?

7
我注意到StackOverflow上已经有一些其他的结果,但它们似乎不起作用或者含糊不清。使用最流行的结果,我整理出了如下内容:
问题在于当JSON返回并被序列化为我的自定义类型之一时,其中一个JSON位有时是一个数组,有时只是一个字符串。如果我的自定义类型是一个字符串,而JSON是一个数组,则会发生错误。相反,如果JSON是一个对象而我的自定义类型是一个数组,也会发生同样的情况。它无法将其映射到属性。
我决定解决这个问题,我想要覆盖此特定属性的反序列化,如果它是一个对象,我想要将其转换为一个只包含1个对象的数组。
在我要序列化的对象中,我添加了一个JsonConverter,我认为它将覆盖它的反序列化方式。
[JsonConverter(typeof(ArrayOrSingleObjectConverter<string>))]
public List<string> person { get; set; }

这个想法是自定义转换器将把单个对象转换为数组。因此,如果JSON是“Hello”,它将设置person为一个包含“Hello”的列表,而不是抛出异常,说无法将字符串转换为List。

如果它已经是一个数组,它应该保持不变。

转换器看起来像这样:

public class ArrayOrSingleObjectConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true; // Not sure about this but technically it can accept an array or an object, so everything is game.
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (objectType == typeof(List<T>))
        {
            return serializer.Deserialize<List<T>>(reader);
        }
        else
        {
            var singleObject = serializer.Deserialize<T>(reader);
            var objectAsList = new List<T>();
            objectAsList.Add(singleObject);
            return objectAsList;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

它不起作用。以上代码在if语句中抛出异常,试图将一个单独的字符串反序列化为List('objectype'确实是List),但无法转换。
我很难理解读写方法到底在做什么。在stackoverflow上的其他答案中,建议在读取方法中抛出NotImplementedException。但是如果我这样做,读取方法就会被调用并抛出异常。
我认为我走在正确的路上,但我需要指点一下方向。我觉得我有点困惑ReadJSon方法在做什么以及它的参数的含义是什么。
我真的不明白它正在反序列化的值来自何处,因为我没有在Deserialize方法调用中指定它。
我对此有点摸不着头脑。

你不能将那个“variable”对象反序列化为System.Object吗?然后你可以检查运行时类型并进行操作。 - Tejas Sharma
2个回答

9

上周我也遇到了类似的问题,我想出了下面的解决方案。对于一个列表而不是一个数组,这个方法效果很好。

 internal class GenericListCreationJsonConverter<T> : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            return serializer.Deserialize<List<T>>(reader);
        }
        else
        {
            T t = serializer.Deserialize<T>(reader);
            return new List<T>(new[] { t });
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

非常感谢,最终我自己也想出了类似的方法,但是我很喜欢你的方法,因为我在泛型方面遇到了困难 :) - NibblyPig

3

我喜欢这种方法,它让Json.NET来处理所有繁琐的工作。结果,它支持Json.NET所支持的任何内容(List<>、ArrayList、强类型数组等)。

public class FlexibleCollectionConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            return serializer.Deserialize(reader, objectType);
        }

        var array = new JArray(JToken.ReadFrom(reader));
        return array.ToObject(objectType);
    }

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接