仅当数组为空时,JSON反序列化才会失败

在某些情况下,当我收到其中一个数组属性为空的JSON时,反序列化失败,抛出以下exception:

无法将当前JSON对象(例如{“name”:“value”})反序列化为类型’SonicApi.ClickMark []’,因为该类型需要JSON数组(例如[1,2,3])才能正确反序列化。

要修复此错误,请将JSON更改为JSON数组(例如[1,2,3])或更改反序列化类型,使其成为普通的.NET类型(例如,不是像整数这样的基本类型,而不是类似的集合类型可以从JSON对象反序列化的数组或List。 JsonObjectAttribute也可以添加到类型中以强制它从JSON对象反序列化。

路径auftakt_result.click_marks,第1行,第121位。

尝试使用以下代码忽略空值没有帮助:

var jsonSerializerSettings = new JsonSerializerSettings(); jsonSerializerSettings.NullValueHandling = NullValueHandling.Ignore; 

以下是产生错误的JSON示例:

 { "status": { "code": 200 }, "auftakt_result": { "clicks_per_bar": 0, "overall_tempo": 0, "overall_tempo_straight": 0, "click_marks": {} } } 

以下是JSON的示例,其数组不为空且不会产生任何错误:

 { "status": { "code": 200 }, "auftakt_result": { "clicks_per_bar": 8, "overall_tempo": 144.886978, "overall_tempo_straight": 144.90889, "click_marks": [ { "index": 0, "bpm": 144.226624, "probability": 0.828170717, "time": 0.0787981859, "downbeat": "false" }, { "index": 1, "bpm": 144.226517, "probability": 0.831781149, "time": 0.286802721, "downbeat": "false" }, etc ... 

以下是表示上述对象的C#类型:

 public sealed class AnalyzeTempoResponse { [JsonProperty("auftakt_result")] public AuftaktResult AuftaktResult { get; set; } [JsonProperty("status")] public Status Status { get; set; } } public sealed class Status { [JsonProperty("code")] public int Code { get; set; } } public sealed class AuftaktResult { [JsonProperty("clicks_per_bar")] public int ClicksPerBar { get; set; } [JsonProperty("overall_tempo")] public double OverallTempo { get; set; } [JsonProperty("overall_tempo_straight")] public double OverallTempoStraight { get; set; } [JsonProperty("click_marks")] public ClickMark[] ClickMarks { get; set; } } public sealed class ClickMark { [JsonProperty("index")] public int Index { get; set; } [JsonProperty("bpm")] public double Bpm { get; set; } [JsonProperty("probability")] public double Probability { get; set; } [JsonProperty("time")] public double Time { get; set; } [JsonProperty("downbeat")] public string Downbeat { get; set; } } 

如何反序列化click_marks内容为null的响应?

如果这很重要,我使用的是最新版本的Newtonsoft.Json:v6.0

编辑

根据@ khellang的回答,这是采用的解决方案:

 public class ClickMarkArrayConverter : CustomCreationConverter { public override ClickMark[] Create(Type objectType) { return new ClickMark[] {}; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.StartArray) { return serializer.Deserialize(reader, objectType); } if (reader.TokenType == JsonToken.StartObject) { serializer.Deserialize(reader); // NOTE : value must be consumed otherwise an exception will be thrown return null; } throw new NotSupportedException("Should not occur, check JSON for a new type of malformed syntax"); } } 

它与null值无关(您的JSON示例都没有任何属性的null值)。 您正在尝试将JSON对象反序列化为ClickMark[]

 "click_marks": {} // <-- This is an object, not null, not an array. 

它适用于第二个例子的原因是click_marks属性实际上 ClickMark对象的数组:

 "click_marks": [{...}, {...}, {...}] // <-- This is an array with three objects. 

数据来自哪里? 您需要确保click_marks属性是数组或对象,而不是两者,并且您键入的C#对象ClickMarks匹配JSON属性的“类型”。

如果您无法控制数据,例如,如果它来自第三方,我建议您编写一个可以应用于该单个属性的自定义JsonConverter

 public class ObjectToArrayConverter : CustomCreationConverter { public override T[] Create(Type objectType) { return new T[0]; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.StartArray) { return serializer.Deserialize(reader, objectType); } else { return new T[] { serializer.Deserialize(reader) }; } } } 

并像这样应用它:

 public sealed class AuftaktResult { // ... [JsonProperty("click_marks")] [JsonConverter(typeof(ObjectToArrayConverter))] public ClickMark[] ClickMarks { get; set; } } 

这将检查值是否是单个对象并将其包装在一个数组中,以便它匹配您的C#POCO属性:)