为什么Json.NET无法将JSON数组反序列化为对象属性?

时间:2016-11-22 20:45:47

标签: c# json.net

临时说明:这不是上述帖子的重复

假设我有一个像这样的服务器端类结构。

public class Test
{
    // this can be any kind of "Tag"
    public object Data { get; set; }
}

public class Other
{
    public string Test { get; set; }
}

现在这样的字符串就是来自客户端。

{"Data": [{$type: "MyProject.Other, MyProject", "Test": "Test"}] }

当我尝试将其反序列化为Test实例时,我得到的结果是Tag属性为JToken而不是某种集合,例如{{1} }或ArrayList

我理解List<object>无法反序列化为强类型列表,但我希望它尊重它至少是一个列表。

这是我当前的反序列化代码。

Json.NET

我知道如果我序列化这样的结构,那么默认情况下我会在JSON字符串中获得var settings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto, }; var str = "{\"Data\": [{\"$type\": \"MyProject.Other, MyProject\", \"Test\": \"Test\"}] }"; var test = JsonConvert.Deserialize<Test>(str, settings); // this first assertion fails (test.Data is IList).ShouldBeTrue(); (((IList)test.Data)[0] is Other).ShouldBeTrue(); 结构而不是纯数组文字,这确实会正确地反序列化。但是,客户端正在发送一个纯数组文字,所以我应该能够以某种方式处理它。

2 个答案:

答案 0 :(得分:1)

我成功地组建了一个JsonConverter来处理这类无类型列表。当目标类型为object时,转换器适用。然后,如果当前令牌类型是数组start([),它将强制反序列化为List<object>。在任何其他情况下,它将回退到正常反序列化。

这是第一个通过我最重要的单元测试的版本,但由于我不是Json.NET专家,它可能会意外地破坏一些事情。如果有人看到我没有看到的任何内容,请发表评论。

public class UntypedListJsonConverter : JsonConverter
{
    public override bool CanWrite => false;
    public override bool CanRead => true;

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

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

        return serializer.Deserialize<List<object>>(reader);
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object);
    }
}

用法示例:

var settings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Auto,
    Converters = new[] { new UntypedListJsonConverter() }
};

var str = "{\"Data\": [{\"$type\": \"MyProject.Other, MyProject\", \"Test\": \"Test\"}] }";
var test = JsonConvert.Deserialize<Test>(str, settings);
// now these assertions pass
(test.Data is IList).ShouldBeTrue();
(((IList)test.Data)[0] is Other).ShouldBeTrue();

答案 1 :(得分:0)

试试这个:

public class Test
{
    public Dictionary<string, List<Other>> Data { get; } = new Dictionary<string, List<Other>>();
}

您需要设置要从json数据填充的类,以便与json结构紧密匹配。从它的外观来看,json看起来是一个字典,其中键是字符串,值是Other个对象的数组。