如何根据数据中的属性值选择要使用Json.Net反序列化的对象类型

本文关键字:Json Net 类型 对象 反序列化 选择 何根 数据 属性 | 更新日期: 2023-09-27 18:20:32

我需要像这样反序列化json(它是DICOM中定义的,这是一个国际标准,所以我不能更改格式!)

{
....
"00080060": {
  "Value": [
    "US"
  ],
  "vr": "CS"
},
"00080070": {
  "Value": [
    "ACME Products"
  ],
  "vr": "LO"
},
"00080090": {
  "Value": [
    {
      "AlphabeticName": "Better^Make^U.^MD"
    }
  ],
  "vr": "PN"
},
"00081110": {
  "Value": [
    {
      "00080008": {
        "Value": [
          "XX_0",
          "OIU",
          null,
          "PPP"
        ],
        "vr": "CS"
      }
    },
    {},
    {
      "00080008": {
        "Value": [
          "XX_2",
          "OIU",
          null,
          "PPP"
        ],
        "vr": "CS"
      }
    }
  ],
  "vr": "SQ"
},

每个属性(在一个长列表中!)都有一个名称(上例中为0008XXXX),并有子属性"vr"和Value。在大多数情况下,Value只是一个对象数组(字符串或数字),这很好,但对于2种特殊情况(如上所述的PN和SQ),它需要特殊处理,而在SQ的情况下,它实际上又是一个顶级对象数组(可以无限递归嵌套…)

那么,我需要的是一个简单的方法,在反序列化过程中检查"vr"值,并为json.net提供它应该用于关联"value"的类型,有简单的方法吗?当然,虚拟现实可能出现在Value之前或之后(取决于远程实现),这可能会使事情进一步复杂化。。。

我已经研究了json.net的ContractResolver和JsonConverter机制,但ContractResolver似乎不允许我访问正在读取的数据以进行选择,JsonConverter派生的类似乎让我不得不重新实现json.net的大部分功能(否则就太好了!):-(

我是不是错过了一些显而易见的简单解决方案?

如何根据数据中的属性值选择要使用Json.Net反序列化的对象类型

Ugh,这是一种很难使用的格式。但是,应该可以使用自定义JsonConverter来理解它。在转换器内部使用JObject将保护我们免受大部分繁重的工作。但首先,我们需要定义几个类来将数据反序列化为。

第一堂课我会叫Node;这将包含CCD_ 4列表和CCD_。

class Node
{
    public IList Value { get; set; }
    public string vr { get; set; }
}

第二类用于存放"PN"情况下的项目。

class PnItem
{
    public string AlphabeticName { get; set; }
}

这是转换器的代码。转换器可以查看vr属性,并使用该信息为Value创建正确类型的列表。

class NodeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Node));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        Node node = new Node();
        node.vr = (string)jo["vr"];
        if (node.vr == "PN")
        {
            node.Value = jo["Value"].ToObject<List<PnItem>>(serializer);
        }
        else if (node.vr == "SQ")
        {
            node.Value = jo["Value"].ToObject<List<Dictionary<string, Node>>>(serializer);
        }
        else
        {
            node.Value = jo["Value"].ToObject<List<string>>(serializer);
        }
        return node;
    }
    public override bool CanWrite
    {
        get { return false; }
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

请注意,对于"SQ"情况,我们正在反序列化List<Dictionary<string, Node>>。这涵盖了递归结构。每当Json.Net试图反序列化Node时,它都会回调到转换器中。我们使用Dictionary来处理属性名称可能变化的事实(例如"00080070"、"00080090"等)。在根目录中,出于同样的原因,我们还必须反序列化为Dictionary<string, Node>

因此,为了将其结合在一起,以下是如何反序列化JSON:

var dict = JsonConvert.DeserializeObject<Dictionary<string, Node>>(json, 
                                                            new NodeConverter());

下面是一个演示:https://dotnetfiddle.net/hsFlxU