如何反序列化可以是数组或单个对象的JSON

kra*_*fan 5 vb.net json json.net

我对使用JSON.net相当陌生,遇到一些json时遇到了麻烦,我有时会以数组的形式出现,有时以单个对象的形式出现。这是我在json中看到的示例

一种进来的方式...

{
  "Make": "Dodge",
  "Model": "Charger",
  "Lines": [
    {
      "line": "base",
      "engine": "v6",
      "color": "red"
    },
    {
      "line": "R/T",
      "engine": "v8",
      "color": "black"
    }
  ],
  "Year": "2013"
}
Run Code Online (Sandbox Code Playgroud)

它可能进入的另一种方式

{
  "Make": "Dodge",
  "Model": "Charger",
  "Lines": {
    "line": "base",
    "engine": "v6",
    "color": "red"
  },
  "Year": "2013"
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

我猜想这可能需要一个自定义的JsonConverter,但是我对如何设置它有些困惑。

Bri*_*ers 5

以下是如何SingleOrArrayConverter在链接的重复问题中获得适用于您的用例的解决方案。

首先,这里是VB翻译的转换器代码。将其保存到项目中某处的类文件中。然后,您可以轻松地将其重用于任何类似的未来案例。

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
Run Code Online (Sandbox Code Playgroud)

现在你有了这个转换器,任何时候你有一个可以是列表或单个项目的属性,你所要做的就是在你的类中将它声明为一个列表,然后用一个JsonConverter属性注释该列表,以便它使用在SingleOrArrayConverter类。在你的情况下,这看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

然后,像往常一样反序列化,它会按预期工作。

Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json)
Run Code Online (Sandbox Code Playgroud)

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


Kun*_*han 1

您可以通过修改您的jsonCar课程来实现此目的,如下所示

Public Class jsonCar
    Public Property make As String 
    Public Property model As String
    Public Property linesCollection As List(Of jsonCarLines) // Change name
    Public Property lines As String // Change the type to string
    Public Property year As String
End Class
Run Code Online (Sandbox Code Playgroud)

代码应该如下所示:

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

If (car.lines.StartsWith("[")) Then
    car.linesCollection = JsonConvert.DeserializeObject(List(Of jsonCarLines))(car.lines)
Else
    car.linesCollection = new List(Of jsonCarLines)
    car.linesCollection.Add(JsonConvert.DeserializeObject(Of jsonCarLines)(car.lines))
EndIf
Run Code Online (Sandbox Code Playgroud)