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

时间:2015-02-08 15:26:27

标签: json vb.net 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"
}

它可以进入的另一种方式

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

以下是我一直用于第一种方式的代码并在第二种情况下引发异常的内容。在网上搜索实现这一点的方法,我真的被卡住了。

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,但我有点不知道如何设置它。

4 个答案:

答案 0 :(得分:4)

以下是如何让链接duplicate question中的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

现在您拥有了这个转换器,只要您拥有可以是列表或单个项目的属性,您只需将其声明为类中的列表,然后使用{{注释该列表1}}属性使得它使用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

以下是完整演示:https://dotnetfiddle.net/msYNeQ

答案 1 :(得分: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

代码应如下所示:

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

答案 2 :(得分:0)

您可以通常反序列化为Object,然后检查您拥有的内容。您可以检查JArray或JObject并采取相应措施。您甚至不需要反序列化为特定类型,您可以使用动态对象,但这可能不是最好的主意。

    Module Module1

    Sub Main()
     Dim jsonWithArray As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": [{""line"":""base"",""engine"": ""v6"",""color"":""red""},{""line"":""R/T"",""engine"":""v8"",""color"":""black""}],""Year"":""2013""}"
     Dim jsonWithObject As String = "{""Make"":""Dodge"",""Model"":""Charger"",""Lines"": {""line"":""base"",""engine"": ""v6"",""color"":""red""},""Year"":""2013""}"

     Dim witharray As Newtonsoft.Json.Linq.JObject = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonWithArray)
     Dim withstring As Newtonsoft.Json.Linq.JObject = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonWithObject)

     Dim jtokArray As Newtonsoft.Json.Linq.JToken = witharray("Lines")
     Dim jtokStr As Newtonsoft.Json.Linq.JToken = withstring("Lines")

     If (jtokArray.GetType() Is GetType(Newtonsoft.Json.Linq.JArray)) Then
        Console.WriteLine("its an array")
     End If

     If (jtokStr.GetType() Is GetType(Newtonsoft.Json.Linq.JObject)) Then
        Console.WriteLine("its an object")
     End If

    Console.ReadKey()

    End Sub

End Module

答案 3 :(得分:0)

感谢crowcoder&amp; Kundan。我结合了这两种方法,并提出了适用于两种json输入的东西。这是最终的代码。

Public Class jsonCar
    Public Property make As String
    Public Property model As String
    Public Property linesArray 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 obj As JObject = JsonConvert.DeserializeObject(json)
        Dim ln As JToken = obj("Lines")

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

        If (ln.GetType() Is GetType(Newtonsoft.Json.Linq.JArray)) Then
            car.linesArray = JsonConvert.DeserializeObject(Of List(Of jsonCarLines))(JsonConvert.SerializeObject(ln))
        End If

        If (ln.GetType() Is GetType(Newtonsoft.Json.Linq.JObject)) Then
            car.linesArray = New List(Of jsonCarLines)
            car.linesArray.Add(JsonConvert.DeserializeObject(Of jsonCarLines)(JsonConvert.SerializeObject(ln)))
        End If

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

End Module

非常感谢快速回复。这解决了我花了很多时间试图弄明白的事情。