我怎样才能选择一个对象类型,基于数据的属性值使用Json.Net反序列化 [英] How can I select an object type to deserialize using Json.Net based on property values in the data

查看:186
本文介绍了我怎样才能选择一个对象类型,基于数据的属性值使用Json.Net反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要反序列化这样的JSON(它在DICOM定义 - 一个国际标准,所以我不能改变格式)

I need to deserialize json like this (it's as defined in DICOM - an international standard, so I can't change the format!)

{
....
"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的价值。在大多数情况下,值是简单对象数组(字符串或数字),这就是良好,但对于2特殊情况下(PN和SQ如上)它需要特殊的处理,并在SQ的情况下,它实际上是的阵列再次顶级对象(可以递归嵌套循环往复......)

Each property (in a long list!) has a name (0008XXXX in example above), and has sub-properties "vr" and Value. In most cases, Value is simply an array of objects (string or number) and that's fine, but for 2 special cases (PN and SQ as above) it needs special handling, and in the case of SQ it is actually an array of the top level object again (which can be nested recursively ad infinitum...)

所以 - 我需要的是一个简单的方法,反序列化过程视察VR的价值并给予json.net应该为相关的值使用类型 - 有一个简单的方法来做到这一点?当然,事实上,VR可以来之前或之后的价值(取决于远程实现)可能使事情变得复杂进一步...

So - what I need is a simple method, during deserialization to inspect the "vr" value and to give json.net the type it should use for the associated "Value" - is there a simple means to do that? Of course, the fact that vr could come before or after Value (depending on remote implementation) might complicate things further...

我看了json.net的ContractResolver和JsonConverter机制,但ContractResolver似乎没有给我访问的数据被读取,以便让做出的选择,JsonConverter派生类似乎离开我不得不重新实现大部分json.net是洞(否则!这么好)我已经: - (

I've looked at json.net's ContractResolver and JsonConverter mechanisms, but ContractResolver seems not to give me access to the data being read in order to allow to make the choice, and JsonConverter derived classes would seem to leave me having to re-implement most of what json.net is dong (otherwise so well!) for me already :-(

我缺少一些明显和简单的解决方案在这里

Am I missing some obvious and simple solution here?

推荐答案

呃,这是一个很难处理的格式,但它应该是可能使使用自定义它的意义 JsonConverter 。使用 JObject 里面的转换器将保护我们从最繁重的工作。但首先,我们需要定义几个类的数据反序列化为。

Ugh, this is a difficult format to work with. However, it should be possible to make sense of it using a custom JsonConverter. Using a JObject inside the converter will shield us from most of the heavy lifting. But first, we need to define a couple of classes to deserialize the data into.

第一类我称之为节点;这将包含列表和 VR

The first class I'll call Node; this will contain the Value list and vr.

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



需要第二类为持有项目为PN案

The second class is needed for holding the items for the "PN" case.

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

下面是转换的代码。该转换器可以看看 VR 属性,并使用这些信息来创建正确类型列表中。<的/ p>

Here is the code for the converter. The converter can look at the vr property and use that information to create the correct type of list for the 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案一个列表与LT;字典<字符串,节点GT;> 。这包括递归结构。每当Json.Net试图反序列化节点,它会回调到转换器。我们使用词典来处理的事实属性名称可能不同(例如00080070,00080090等)。在根,我们也必须反序列化到词典<字符串,节点方式> 出于同样的原因

Notice that for the "SQ" case we are deserializing a List<Dictionary<string, Node>>. This covers the recursive structure. Whenever Json.Net tries to deserialize a Node, it will call back into the converter. We use a Dictionary to handle the fact that the property names can vary (e.g. "00080070", "00080090", etc.). At the root, we must also deserialize to a Dictionary<string, Node> for the same reason.

所以, ,将比分扳成都在一起,这里是你将如何反序列化JSON:

So, to tie it all together, here is how you would deserialize your JSON:

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

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

这篇关于我怎样才能选择一个对象类型,基于数据的属性值使用Json.Net反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆