Json.net反序列化来自JSon的对象,可能包含数组或嵌套数组

时间:2014-02-21 17:21:07

标签: c# json.net

我有许多JSon文件,我正在使用

进行反序列化

JsonSerializer serializer = new JsonSerializer(); t obj = (t)serializer.Deserialize(file, typeof(t));

到一组对象。它们包含以下数据。 “facttable”中的数组数量由“gates”的值决定

"gates" : 1,
"truthtable" : [ false, true ]

"gates" : 2,
"truthtable" : [ [ false, false ], [ false, true ] ]

如果我尝试将“facttable”反序列化为以下属性,则示例1失败。

public List<List<bool>>truthtable { get; set; }

有什么方法可以将这两种不同类型的真值表反序列化到同一个对象中?我已经尝试构建一个自定义反序列化器,但Json将它们视为“JsonToken.StartArray”,因此无法区分这种方式。

理想情况下,我希望能够将这两个示例反序列化,就像它们是布尔数组的数组一样。

修改 应该提到,我不能改变Json文件的创建方式。我无权访问他们的作品。

4 个答案:

答案 0 :(得分:1)

使用自定义JsonConverter可以解决此问题。转换器可以读取门的数量,然后相应地填充List<List<bool>>。如果只有一个门,它可以将单个列表包装在外部列表中,以使其适用于您的类。

假设您尝试反序列化的类看起来像这样:

class Chip
{
    public int Gates { get; set; }
    public List<List<bool>> TruthTable { get; set; }
}

然后转换器可能看起来像这样:

class ChipConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Chip));
    }

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

        Chip chip = new Chip();
        chip.Gates = (int)jo["gates"];
        JArray ja = (JArray)jo["truthtable"];

        if (chip.Gates == 1)
        {
            chip.TruthTable = new List<List<bool>>();
            chip.TruthTable.Add(ja.ToObject<List<bool>>());
        }
        else
        {
            chip.TruthTable = ja.ToObject<List<List<bool>>>();
        }

        return chip;
    }

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

要使用转换器,请在反序列化之前创建一个实例并将其添加到序列化程序的Converters集合中:

serializer.Converters.Add(new ChipConverter());

或者,如果您愿意,可以使用[JsonConverter]属性注释您的课程:

[JsonConverter(typeof(ChipConverter))]
class Chip
{
    ...
}

这是一个演示转换器运行的演示(注意我在这里使用JsonConvert.DeserializeObject<T>()而不是创建JsonSerializer实例,但它的工作原理相同):

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        [
            {
                ""gates"": 1,
                ""truthtable"": [ false, true ]
            },
            {
                ""gates"": 2,
                ""truthtable"": [ [ false, false ], [ false, true ] ]
            }
        ]";

        List<Chip> chips = JsonConvert.DeserializeObject<List<Chip>>(json,
                                                         new ChipConverter());

        foreach (Chip c in chips)
        {
            Console.WriteLine("gates: " + c.Gates);
            foreach (List<bool> list in c.TruthTable)
            {
                Console.WriteLine(string.Join(", ",
                    list.Select(b => b.ToString()).ToArray()));
            }
            Console.WriteLine();
        }
    }
}

输出:

gates: 1
False, True

gates: 2
False, False
False, True

答案 1 :(得分:0)

简单...更改生成facttable的方法(在gate == 1的情况下)输出数组的数组(或List&gt;)。

“盖茨”:1, “facttable”:[[false,true]]

请注意,您的数据合同中有一个类型,在这种情况下,数据合同需要一个List&gt;并且您发送了错误的类型(列表&lt;&gt;)。你能写一下在gate == 1 case中生成“facttable”的代码吗?

PS。对不起,我不会说英语...... =)

答案 2 :(得分:0)

假设您使用的是.NET 4.0或更高版本,可以将json反序列化为Dynamic Object

string jsonData = ....; // fill your json data here
dynamic d = JsonConvert.DeserializeObject(jsonData);

然后检查d.truthtable[0]的类型并确定当d.truthtable是数组或嵌套数组时要执行的操作

if (d.truthtable != null && d.truthtable.Count > 0)
{
    if (d.truthtable[0].GetType() == typeof(Newtonsoft.Json.Linq.JValue))
    {
        // do something when truthtable is an array
    }
    else if (d.truthtable[0].GetType() == typeof(Newtonsoft.Json.Linq.JArray))
    {
        // do something when truthtable is a nested array
    }
}

答案 3 :(得分:0)

我假设,这是一个数据合同冲突,我建议一个工作......只考虑性能......

在这种情况下,并不优雅,但是,您可以轻松地更改类型并强制使用数组&gt; ..

String json = ...

        int idx = 0;
        while (idx >-1)
        {
            idx = json.Trim().IndexOf("\"truthtable\":[",idx);
            if (idx >-1 && json[idx + 15] != '[')
            {
                idx += 14;
                json = json.Insert(idx, "[");
                json = json.Insert(json.IndexOf("]", idx),"]");
            }
        }

这对你有帮助吗?