【问题标题】:Deserialize inconsistent JSON property反序列化不一致的 JSON 属性
【发布时间】:2020-07-23 02:16:47
【问题描述】:

希望有人可以帮助我解决我尝试使用 Newtonsoft.Json 反序列化的大型 JSON 文件中出现的以下不一致问题。

对象的其中一个属性偶尔会显示为:

"roles": [
  {
    "field1" : "value",
    "field2" : "value"
  }
]

虽然其他时候相同的属性显示为:

"roles": {
  "roles": [
    {
      "field1" : "value",
      "field2" : "value"
    }
  ]
}

作为参考,该属性在其类中实现为:

[JsonProperty("roles")]
public List<Role> Roles { get; set; }

我需要做的是,每当发生上述第二种情况时,对象内容就会像第一种情况一样反序列化。即“外部”对象被丢弃/忽略

当一个单独的属性有时作为一个对象出现,有时作为一个数组出现时,我已经设法处理了这个文件中的另一个不一致,在其类定义中使用以下方法:

[JsonConverter(typeof(SingleValueArrayConverter<Address>))]
public List<Address> Location { get; set; }

并实现为:

public class SingleValueArrayConverter<T> : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object retVal = new Object();
        if (reader.TokenType == JsonToken.StartObject)
        {
            T instance = (T)serializer.Deserialize(reader, typeof(T));
            retVal = new List<T>() { instance };
        }
        else if (reader.TokenType == JsonToken.StartArray)
        {
            retVal = serializer.Deserialize(reader, objectType);
        }
        return retVal;
    }

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

但是,我无法解决这个问题。 有人可以帮忙吗?

【问题讨论】:

  • 你不能修复实际的错误吗?你要做的是将真正的虫子扫到地毯下,假装它不存在。这将导致更多的痛苦。
  • 嗨@RosdiKasim,不幸的是,我正在反序列化的 JSON 文件是由我无法控制的第 3 方提供的。总共有大约 150 万个对象分布在我正在反序列化的 7 个文件中。我已经成功处理了其中的 6 个文件,但是在这个文件中,出现了这个问题。干杯
  • 第二种情况不是有效的 JSON,除非有错字。需要一个 ] 来匹配 [
  • 道歉@GarrGodfrey 这是一个错字,我已经更正了
  • 糟糕。您可以尝试识别这种情况,就像在另一个示例中一样,但是您需要反序列化为 dynamic,获取第一个属性值,对其进行序列化,然后将其反序列化为正确的类型。

标签: c# json json.net deserialization json-deserialization


【解决方案1】:

您也可以使用JsonConverter 处理这种不一致。它会与您拥有的略有不同,但想法非常相似:

public class ArrayOrWrappedArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(List<T>).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return CreateListFromJArray((JArray)token, serializer);
        }
        if (token.Type == JTokenType.Object)
        {
            JObject wrapper = (JObject)token;
            JProperty prop = wrapper.Properties().FirstOrDefault();
            if (prop.Value.Type == JTokenType.Array)
            {
                return CreateListFromJArray((JArray)prop.Value, serializer);
            }
        }
        // If the JSON is not what we expect, just return an empty list.
        // (Could return null or throw an exception here instead if desired.)
        return new List<T>();
    }

    private List<T> CreateListFromJArray(JArray array, JsonSerializer serializer)
    {
        List<T> list = new List<T>();
        serializer.Populate(array.CreateReader(), list);
        return list;
    }

    public override bool CanWrite => false;

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

然后只需将转换器添加到您的 Roles 属性中,您就可以开始了:

[JsonProperty("roles")]
[JsonConverter(typeof(ArrayOrWrappedArrayConverter<Role>))]
public List<Role> Roles { get; set; }

工作演示:https://dotnetfiddle.net/F6qgQB

【讨论】:

  • 非常感谢!它工作得很好。如果您喜欢冒险,我已经确定了此文件中的最后一个问题,我相信可以以同样的方式处理它,但我正在努力解决它。我在这里问过这个问题stackoverflow.com/questions/63064260/…
【解决方案2】:

最简单的方法(不一定是最干净的)是在反序列化之前手动更改字符串 -

jsonString = jsonString.replace("\"roles\": {", "\"rolesContainer\": {");
jsonString = jsonString.replace("\"roles\":{", "\"rolesContainer\": {");

然后在您的主代码中,您将拥有rolesContainer 和roles 作为字段 - 然后在之后合并它们

public List<Role> roles { get; set; }
public RoleContainer rolesContainer { get; set; }
public class RoleContainer {
    Public List<Role> roles;
}

它很脏,但它应该可以工作

【讨论】:

    猜你喜欢
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多