【问题标题】:Deserialize JSON that might be an integer or a list of strings in C#在 C# 中反序列化可能是整数或字符串列表的 JSON
【发布时间】:2013-12-12 15:37:56
【问题描述】:

我正在使用 C# 反序列化 JSON 字符串的集合。每个字符串都有一个属性employer_normalized,它应该包含stringList<int>,其中List 中的值始终为正数。在某些情况下,employer_normalized 设置为 -1,所以我想用一些将 employer_normalized 设置为 null 的行为来覆盖这些情况。

这是我的课:

public class EmployerNormalized
{
  public string company;
  public List<int> code;
}

良好的 JSON

"employer_normalized": {
        "company": "self",
        "code": [
          "4581 ",
          "6732 ",
          "9121",
          "9999 ",
          "5947 ",
          "8322 ",
          "8351 ",
          "7335 ",
          "9999 ",
          "4225 ",
          "8399 "
        ]
      }

错误的 JSON

"employer_normalized": -1

我目前正在使用Json.NET 进行 JSON 解析。解决这个问题的优雅解决方案是什么?如果是-1,最好将employer_normalized 值设置为null?如果是这样,我该怎么做?

【问题讨论】:

  • 解雇开发生成此 JSON 的应用程序的人 :)
  • 我希望可以。不过,我现在仍然坚持这一点,所以我必须想办法处理这些特定情况。

标签: c# json json.net deserialization


【解决方案1】:

您可以使用自定义的 JsonConverter 来处理这种情况。无论您在哪里期待EmployerNormalized,转换器都可以检查该属性的值是否为-1并返回null,否则正常反序列化。

这是转换器的代码:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            return token.ToObject<EmployerNormalized>();
        }
        return null;
    }

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

这是一个演示如何使用它:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""good"" : {
                ""company"": ""self"",
                ""code"": [
                    ""4581 "",
                    ""6732 "",
                    ""9121"",
                    ""9999 "",
                    ""5947 "",
                    ""8322 "",
                    ""8351 "",
                    ""7335 "",
                    ""9999 "",
                    ""4225 "",
                    ""8399 ""
                ]
            },
            ""bad"" : -1
        }";

        Wrapper wrapper =
            JsonConvert.DeserializeObject<Wrapper>(json, 
                new EmployerNormalizedConverter());

        DumpEmployer("good", wrapper.good);
        DumpEmployer("bad", wrapper.bad);
    }

    private static void DumpEmployer(string prop, EmployerNormalized emp)
    {
        Console.WriteLine(prop);
        if (emp != null)
        {
            Console.WriteLine("  company: " + emp.company);
            Console.WriteLine("  codes: " + 
                string.Join(", ", emp.code.Select(c => c.ToString())));
        }
        else
            Console.WriteLine("  (null)");
    }

    public class Wrapper
    {
        public EmployerNormalized good { get; set; }
        public EmployerNormalized bad { get; set; }
    }

    public class EmployerNormalized
    {
        public string company;
        public List<int> code;
    }
}

这是输出:

good
  company: self
  codes: 4581, 6732, 9121, 9999, 5947, 8322, 8351, 7335, 9999, 4225, 8399
bad
  (null)

重要提示:您可能很想用[JsonConverter(typeof(EmployerNormalizedConverter))] 来装饰EmployerNormalized 类,但如果您这样做,那么当前形式的转换器最终会递归调用自己直到出现StackOverflowException 错误。如果您需要/想要使用该属性,则需要更改转换器中 ReadJson 方法的代码,以便它手动创建 EmployerNormalized 类的实例并单独填充其所有属性,而不是调用token.ToObject&lt;EmployerNormalized&gt;()。这是ReadJson 的替代版本,可以避免递归问题:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    JToken token = JToken.Load(reader);
    if (token.Type == JTokenType.Object)
    {
        EmployerNormalized employer = new EmployerNormalized();
        employer.company = token["company"].ToString();
        employer.code = token["code"].ToObject<List<int>>();
        return employer;
    }
    return null;
}

【讨论】:

  • 这太完美了!谢谢!
  • 没问题;很高兴为您提供帮助。
  • 知道为什么我会收到这个错误吗? An unhandled exception of type 'System.StackOverflowException' occurred in Newtonsoft.Json.dll。我正在处理包含EmployerNormalized 对象的对象列表。
  • 您是否在EmployerNormalized 类上使用JsonConverter 属性?如果是这样,那将导致转换器递归调用自身。
【解决方案2】:

我知道这很糟糕,但是您可以先尝试使用 Good JSON 的结构将 JSON string 解析为 Object,如果出现解析错误,请解析到第二个大小写(错误的 JSON)。

【讨论】:

  • 所以你的意思是我应该创建一个代表错误 JSON 的类并在出现异常的情况下对其进行解析?
  • 差不多 - 尴尬
  • 我认为最简单的解决方案是将employer_normalized 设置为null,但我只需要注意这一点,因为我计划将这些记录插入数据库。如果我将null 值插入不可为空的字段,我的数据库会尖叫。啊!
  • 类似的东西。例如,这个正则表达式 - \"employer_normalized"\:.*\"code\": \[.*\] 检查 json 字符串的一致性(如果它是一个好的 json)。如果不是,您也可以通过正则表达式插入[] 括号。这样一来,您将拥有 code 字段作为数组,其中只有 -1 值。
  • 好主意。我接受了下面的答案,因为我认为这是一个更清洁的解决方案。不过感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多