我有许多JSon文件,我正在使用它们进行反序列化
JsonSerializer serializer = new JsonSerializer();
t obj = (t)serializer.Deserialize(file, typeof(t));
到对象的集合。除其他事项外,它们还包含以下数据。"真值表"中的数组数量由"门"的值决定
"gates" : 1,
"truthtable" : [ false, true ]
和
"gates" : 2,
"truthtable" : [ [ false, false ], [ false, true ] ]
如果我尝试将"Truthtable"反序列化为以下属性,示例 1 将失败。
public List<List<bool>>truthtable { get; set; }
有什么方法可以将这两种不同类型的真值反序列化为同一对象?我尝试构建一个自定义反序列化器,但 Json 将两者都视为"JsonToken.StartArray",因此无法区分。
理想情况下,我希望能够反序列化这两个示例,就好像它们是布尔数组的数组一样。
编辑应该提到,我无法更改 Json 文件的创建方式。我无法访问他们的创作。
这个问题可以使用自定义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 的情况下)更改为输出数组(或 List>)。
"门" : 1,"真值" : [ 假,真 ]]
请记住,数据协定中有一个类型,在这种情况下,数据协定需要一个列表>而你发送了一个错误的类型(List<>)。你能写出在门 == 1 个案例中生成"真相表"的代码吗?
对不起,我的英语说得不太好... =)
假设使用的是 .NET 4.0 或更高版本,则可以将 json 反序列化为动态对象
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
}
}
我假设,这是一个数据契约冲突,我建议一个工作...只考虑性能...
在这种情况下,并不优雅,但是,您可以轻松更改类型并强制 truthtable 为 Array>.。
字符串 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),"]");
}
}
这对你有帮助??