如何使用 Json.Net 反序列化嵌套的 JSON 数组?

How to deserialize nested JSON arrays with Json.Net?

我想反序列化 HTTP 请求对对象的响应。
响应如下所示:

[
    "BeginOfEnumerable",
    [
        {
            "StatusID": 12345,
            "ItemID": 987654
        }
    ],
    "EndOfEnumerable"
]

我正在使用 Newtonsoft.Json。

我尝试使用 Visual Studio 的 Edit > Paste special > Paste JSON as Classes 来创建 class 模型,但结果对我来说很奇怪:

Public Class Rootobject
        Public Property Property1() As Object
End Class

此外,这会引发异常:

Dim myObject As Rootobject = JsonConvert.DeserializeObject(response.Content)

» Unexpected character encountered while parsing value: .Path ", line 0, position 0.

我想要 StatusIDItemID
我使用的 JSON 验证器说这个 JSON 是有效的。

JSON 结构本身是有效的,您可能对不遵循 name:value 模式的字符串有些困难。

您可以仅将内部值数组反序列化为 List(class),例如,

Imports System.Collections.Generic
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq

Public Class EnumObject
    Public Property StatusId As Long
    Public Property ItemId As Long
End Class

'[...]

Dim jsonEnumsTokens = JArray.Parse(response.Content)
Dim enumsArray = jsonEnumsTokens.Children.Skip(1).First().ToObject(Of List(Of EnumObject))()

其中 returns 包含值的 EnumObject 列表,如果这就是您感兴趣的全部并且您不需要以任何其他方式处理此 JSON ,或以相同的形式将其序列化。

如果您只想获得数组的 JSON 表示:

Dim justTheArraysJson = jsonEnumsTokens.Children.Skip(1).First().ToString()

如果你想执行反序列化和序列化,维护结构,你可以使用自定义的 JsonConverter 来处理这个 case.

EnumObjectsConverter 创建一个 中间 结构,其中包含单个字符串和值数组,包含在 EnumObjectArray 属性 .
如果需要,这还允许序列化回原始结构。

称其为:

Dim enumArray = EnumObjectsHandler.Deserialize(response.Content)
Dim serialized = EnumObjectsHandler.Serialize(enumArray)

提供序列化静态方法的EnumObjectsHandlerclass:

Public Class EnumObjectsHandler
    Private Shared settings As JsonSerializerSettings = New JsonSerializerSettings() With {
        .Converters = {New EnumObjectsConverter()}
    }
    Public Shared Function Deserialize(json As String) As List(Of EnumObjectsRoot)
        Return JsonConvert.DeserializeObject(Of List(Of EnumObjectsRoot))(json, settings)
    End Function

    Public Shared Function Serialize(data As List(Of EnumObjectsRoot)) As String
        Return JsonConvert.SerializeObject(data, settings)
    End Function

    Public Class EnumObject
        Public Property StatusId As Long
        Public Property ItemId As Long
    End Class

    Public Structure EnumObjectsRoot
        Public Property EnumObjectArray As List(Of EnumObject)
        Public Property Operation As String

        Public Shared Widening Operator CType(objectArray As List(Of EnumObject)) As EnumObjectsRoot
            Return New EnumObjectsRoot With {.EnumObjectArray = objectArray}
        End Operator

        Public Shared Widening Operator CType(op As String) As EnumObjectsRoot
            Return New EnumObjectsRoot With {.Operation = op}
        End Operator
    End Structure


    Friend Class EnumObjectsConverter
        Inherits JsonConverter

        Public Overrides Function CanConvert(t As Type) As Boolean
            Return t Is GetType(EnumObjectsRoot)
        End Function

        Public Overrides Function ReadJson(reader As JsonReader, t As Type, existingValue As Object, serializer As JsonSerializer) As Object
            Select Case reader.TokenType
                Case JsonToken.String
                    Dim stringValue = serializer.Deserialize(Of String)(reader)
                    Return New EnumObjectsRoot() With {
                        .Operation = stringValue
                    }
                Case JsonToken.StartArray
                    Dim arrayValue = serializer.Deserialize(Of List(Of EnumObject))(reader)
                    Return New EnumObjectsRoot() With {
                        .EnumObjectArray = arrayValue
                    }
            End Select
            Throw New Exception("EnumObjectsRoot could not be deserialized")
        End Function

        Public Overrides Sub WriteJson(writer As JsonWriter, untypedValue As Object, serializer As JsonSerializer)
            Dim value = CType(untypedValue, EnumObjectsRoot)
            If value.Operation IsNot Nothing Then
                serializer.Serialize(writer, value.Operation)
                Return
            End If
            If value.EnumObjectArray IsNot Nothing Then
                serializer.Serialize(writer, value.EnumObjectArray)
                Return
            End If
            Throw New Exception("EnumObjectsRoot could not be serialized")
        End Sub
    End Class
End Class