如何反序列化可以是数组或单个对象的JSON [英] How to deserialize JSON which can be an array or a single object

查看:75
本文介绍了如何反序列化可以是数组或单个对象的JSON的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始使用JSON.net并遇到一些json麻烦,所以我有时会以数组的形式出现,有时以单个对象的形式出现.这是我在json中看到的示例

I'm fairly new to using JSON.net and having trouble with some json I'm getting which sometime comes in as an array and sometimes as single object. Here is an example of what I'm seeing with the json

它进来的一种方式...

One way it comes in ...

{
  "Make": "Dodge",
  "Model": "Charger",
  "Lines": [
    {
      "line": "base",
      "engine": "v6",
      "color": "red"
    },
    {
      "line": "R/T",
      "engine": "v8",
      "color": "black"
    }
  ],
  "Year": "2013"
}

它可以进入的另一种方式

Another way it could come in

{
  "Make": "Dodge",
  "Model": "Charger",
  "Lines": {
    "line": "base",
    "engine": "v6",
    "color": "red"
  },
  "Year": "2013"
}

这是我一直在使用的代码,它在第一种情况下有效,而在第二种情况下抛出异常.一直在网上搜寻实现此方法的方法,并确实陷入困境.

Here is what I've been using for code which works on the first way and throws an exception in the second case. Been scouring the web for ways to implement this and am really stuck.

Public Class jsonCar
    Public Property make As String
    Public Property model As String
    Public Property lines As List(Of jsonCarLines)
    Public Property year As String
End Class

Public Class jsonCarLines
    Public Property line As String
    Public Property engine As String
    Public Property color As String
End Class

Module Module1
    Private Const json As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": [{""line"":""base"",""engine"": ""v6"",""color"":""red""},{""line"":""R/T"",""engine"":""v8"",""color"":""black""}],""Year"":""2013""}"
    'Private Const json As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": {""line"":""R/T"",""engine"":""v8"",""color"":""black""},""Year"":""2013""}"
    Sub Main()
        Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json)

        Console.WriteLine("Make: " & car.make)
        Console.WriteLine("Model: " & car.model)
        Console.WriteLine("Year: " & car.year)
        Console.WriteLine("Lines: ")
        For Each ln As jsonCarLines In car.lines
            Console.WriteLine("    Name: " & ln.line)
            Console.WriteLine("    Engine: " & ln.engine)
            Console.WriteLine("    Color: " & ln.color)
            Console.WriteLine()
        Next
        Console.ReadLine()
    End Sub

End Module

我猜想这可能需要一个自定义的JsonConverter,但是我对如何设置它有点不知所措.

I'm guessing this will likely need a custom JsonConverter, but I'm a bit at a loss as to how to set that up.

推荐答案

以下是如何在链接的重复的问题适用于您的用例.

Here is how to get the SingleOrArrayConverter solution in the linked duplicate question working for your use case.

首先,这是VB转换的转换器代码.将此并保存到项目中某个位置的类文件中.然后,您可以轻松地在以后的任何情况下重用它.

First, here is the VB-translated converter code. Take this and save it to a class file somewhere in your project. You can then easily reuse it for any future cases like this.

Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq

Public Class SingleOrArrayConverter(Of T)
    Inherits JsonConverter

    Public Overrides Function CanConvert(objectType As Type) As Boolean
        Return objectType = GetType(List(Of T))
    End Function

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        Dim token As JToken = JToken.Load(reader)

        If (token.Type = JTokenType.Array) Then
            Return token.ToObject(Of List(Of T))()
        End If

        Return New List(Of T) From {token.ToObject(Of T)()}
    End Function

    Public Overrides ReadOnly Property CanWrite As Boolean
        Get
            Return False
        End Get
    End Property

    Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
        Throw New NotImplementedException
    End Sub

End Class

现在有了此转换器,只要您拥有一个可以是列表或单个项目的属性,您要做的就是将其声明为类中的列表,然后用属性,以便它使用SingleOrArrayConverter类.在您的情况下,看起来像这样:

Now that you have this converter, any time you have a property that can be either a list or a single item, all you have to do is declare it as a list in your class and then annotate that list with a JsonConverter attribute such that it uses the SingleOrArrayConverter class. In your case, that would look like this:

Public Class jsonCar
    Public Property make As String
    Public Property model As String
    <JsonConverter(GetType(SingleOrArrayConverter(Of jsonCarLines)))>
    Public Property lines As List(Of jsonCarLines)
    Public Property year As String
End Class

然后,按照通常的方式反序列化,即可正常使用.

Then, just deserialize as you normally would, and it works as expected.

Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json)

这是一个完整的演示: https://dotnetfiddle.net/msYNeQ

Here is a complete demonstration: https://dotnetfiddle.net/msYNeQ

这篇关于如何反序列化可以是数组或单个对象的JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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