首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何反序列化可以是数组或单个对象的JSON

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

Stack Overflow用户
提问于 2015-02-08 23:26:27
回答 4查看 11.8K关注 0票数 5

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

其中一种方式是……

代码语言:javascript
运行
复制
{
  "Make": "Dodge",
  "Model": "Charger",
  "Lines": [
    {
      "line": "base",
      "engine": "v6",
      "color": "red"
    },
    {
      "line": "R/T",
      "engine": "v8",
      "color": "black"
    }
  ],
  "Year": "2013"
}

它可以通过另一种方式进入

代码语言:javascript
运行
复制
{
  "Make": "Dodge",
  "Model": "Charger",
  "Lines": {
    "line": "base",
    "engine": "v6",
    "color": "red"
  },
  "Year": "2013"
}

下面是我在代码中使用的代码,它在第一种情况下工作,在第二种情况下抛出异常。我一直在网上寻找实现这一点的方法,我真的卡住了。

代码语言:javascript
运行
复制
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,但是我不知道如何设置它。

EN

回答 4

Stack Overflow用户

发布于 2015-02-09 07:02:16

下面是如何让链接的duplicate question中的SingleOrArrayConverter解决方案适用于您的用例。

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

代码语言:javascript
运行
复制
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

现在您有了这个转换器,任何时候您的属性既可以是列表,也可以是单个项,您所要做的就是在类中将其声明为列表,然后使用JsonConverter属性注释该列表,以便它使用SingleOrArrayConverter类。在您的示例中,它将如下所示:

代码语言:javascript
运行
复制
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

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

代码语言:javascript
运行
复制
Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json)

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

票数 5
EN

Stack Overflow用户

发布于 2015-02-08 23:44:31

您可以通过如下方式修改jsonCar类来实现这一点

代码语言:javascript
运行
复制
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

代码应如下所示:

代码语言:javascript
运行
复制
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
票数 1
EN

Stack Overflow用户

发布于 2015-02-09 04:54:43

感谢crowcoder和Kundan。我将这两种方法结合起来,想出了一种可以同时使用两种json输入的方法。这是最终的代码。

代码语言:javascript
运行
复制
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

非常感谢你的快速回复。这解决了我花了很多时间断断续续地试图弄清楚的事情。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28395700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档