Json.NET:单个属性的不同JSON模式

时间:2018-04-24 20:41:41

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

我正在使用第三方API,它使用返回的JSON对象快速而松散地运行。在C#中,我试图设置Json.NET来将这些JSON对象反序列化为类,但是我遇到了麻烦:有时相同的属性名称将与几个不同的模式一起使用,具体取决于上下文

这是JSON数据结构的一个示例:

{
    "examples": [{
            "data": "String data",
            "type": "foo"
        }, {
            "data": {
                "name": "Complex data",
                "19": {
                    "owner": "Paarthurnax"
                }
            },
            "type": "complex"
        }, {
            "data": {
                "name": "Differently complex data",
                "21": {
                    "owner": "Winking Skeever"
                }
            },
            "type": "complex"
        }
    ]
}

在发现这种不一致之前,我用这个类代表了第一个例子:

public class Example {
    [JsonProperty("data")]
    public string Data {get; set;}

    [JsonProperty("type"]
    public string DataType {get; set;}
}

# In the main method
Example deserializedObject = JsonConvert.DeserializeObject<Example>(stringData);

现在,这种方法存在两个问题:

  1. &#34;数据&#34; key有两种不同的属性类型。有时它是一个字符串,有时它是一个对象。我可以为内部对象创建一个自定义类,但是Json.NET会抱怨字符串版本。
  2. 当&#34;数据&#34;是一个对象,它的属性名称是不一致的 - 请注意,第二个数据条目有一个名为19的属性,第三个有一个名为21.这些对象的结构是相同的,但由于它们的键名不同,我可以&#39 ; t直接将它们映射到类。
  3. 第一个问题是更紧迫的问题。

    我知道如果有必要,我可以使用JsonExtensionData来解决问题,但我不确定这是否是最好的方法,并且它不能提供任何编译时安全性应用

    将JSON反序列化为C#类的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

您可以使用JsonConverter。这是一个功能齐全的例子:

public class Example
{
    public string StringData { get; set; }

    public ComplexData ComplexData { get; set; }

    public string Type { get; set; }
}

public class ComplexData
{
    public string Name { get; set; }

    [JsonProperty("19")]
    public Foo Nineteen { get; set; }

    [JsonProperty("21")]
    public Foo TwentyOne { get; set; }
}

public class Foo
{
    public string Owner { get; set; }
}

public class FlexibleJsonConverter : 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)
    {
        var examples = new List<Example>();
        var obj = JObject.Load(reader);
        foreach (var exampleJson in obj["examples"])
        {
            var example = new Example { Type = (string)exampleJson["type"] };
            if (example.Type == "complex")
            {
                example.ComplexData = exampleJson["data"].ToObject<ComplexData>();
            }
            else
            {
                example.StringData = (string)exampleJson["data"];
            }

            examples.Add(example);
        }

        return examples.ToArray();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsAssignableFrom(typeof(Example[]));
    }
}

private static void Main()
{
    var json = @"{
                    ""examples"": [{
                            ""data"": ""String data"",
                            ""type"": ""foo""
                        }, {
                            ""data"": {
                                ""name"": ""Complex data"",
                                ""19"": {
                                    ""owner"": ""Paarthurnax""
                                }
                            },
                            ""type"": ""complex""
                        }, {
                            ""data"": {
                                ""name"": ""Differently complex data"",
                                ""21"": {
                                    ""owner"": ""Winking Skeever""
                                }
                            },
                            ""type"": ""complex""
                        }
                    ]
                }";

    var examples = JsonConvert.DeserializeObject<IEnumerable<Example>>(json, new FlexibleJsonConverter());

    foreach (var example in examples)
    {
        Console.WriteLine($"{example.Type}: {example.StringData ?? example.ComplexData.Nineteen?.Owner ?? example.ComplexData.TwentyOne.Owner}");
    }

    Console.ReadKey();
}