【问题标题】:Convert JSON to list with generic types将 JSON 转换为具有泛型类型的列表
【发布时间】:2020-10-21 06:56:45
【问题描述】:

我收到如下 JSON 响应:

{
  "items": [
    {
      "document": {
        "id": "123",
        "title": "title2",
        "description": "Description1",
        "type": "Typ1"
      }
    },
    {
      "document": {
        "id": "456",
        "title": "title2",
        "description": "desctiption2",
        "type": "Type2",
        "Type2Property": "Type2Property"
      }
    }
  ]
}

正如您在上面看到的,我有两个具有不同属性的值(仅作为示例)。 在我的代码中,我有两个类。

public class Type1
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string Type { get; set; }
}

public class Type2
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string Type { get; set; }
    public string Type2Property {get; set;}
}

问题:如何创建一个结合 Type1 和 Type2 的通用列表。未来,我可以拥有更多的TypeX(具有不同的属性)。所以,我想将 JSON 解析成一个通用列表。

更新:我可以通过 JSON 中的 Type 属性过滤 json。

【问题讨论】:

标签: c# json .net


【解决方案1】:

解决此问题的一种方法是创建自定义JsonConverter 并覆盖其ReadJson 方法。

我引入了几个帮助类来解析整个示例 json:

public class TopLevel
{
    public MidLevel[] Items { get; set; }
}

public class MidLevel
{
    public IDocument Document { get; set; }

}

[JsonConverter(typeof(DocumentTypeConverter))]
public interface IDocument
{
}
  • 我创建了一个IDocument 标记界面。如果您愿意,可以使用abstract class
  • 我用JsonConverterAttribute 装饰了界面,并在那里指定了自定义转换器。
  • 我已更改 Type1Type2 类来实现此接口:
public class Type1 : IDocument
{
    ...
    public string Type { get; set; }
}

public class Type2 : IDocument
{
    ...
    public string Type { get; set; }
    public string Type2Property { get; set; }
}

DocumentTypeConverter naive 实现如下所示:
(显然你可以使类型更安全)

public class DocumentTypeConverter : 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 jObject = JObject.Load(reader);
        switch (jObject["type"].Value<string>())
        {
            case "Typ1":
                {
                    var obj = new Type1();
                    serializer.Populate(jObject.CreateReader(), obj);
                    return obj;
                }
            case "Type2":
                {
                    var obj = new Type2();
                    serializer.Populate(jObject.CreateReader(), obj);
                    return obj;
                }
            default:
                throw new Exception();
        }
    }

    public override bool CanConvert(Type objectType) 
        => objectType == typeof(IDocument);
}
  • CanConvert 告诉我们此转换可用于对抗 IDocuments。
  • ReadJson 根据“类型”字段对其逻辑进行分支。
  • 使用Populate 而不是JsonCovert.Deserializeavoid infinite recursion 完成的实际转换。

最后,用法就是这么简单:

static void Main(string[] args)
{
    var sampleJson = File.ReadAllText("sample.json");
    var sample = JsonConvert.DeserializeObject<TopLevel>(sampleJson);
    Console.ReadLine();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-26
    • 2010-12-02
    • 2016-02-02
    • 1970-01-01
    • 2016-05-05
    • 1970-01-01
    • 2013-01-08
    相关资源
    最近更新 更多