在 Visual Basic .NET 中反序列化 JSON

Posted

技术标签:

【中文标题】在 Visual Basic .NET 中反序列化 JSON【英文标题】:Deserializing JSON in Visual Basic .NET 【发布时间】:2015-11-01 13:33:14 【问题描述】:

想知道您是否可以帮助我创建一个 VB.Net 类,我可以将以下 JSON 响应反序列化为该类:


  "id":86,
  "name":"Tom",
  "likes":
         
         "actors":[
                    ["Clooney",2,30,4],
                    ["Hanks",104,15,1]
                  ]
         ,
  "code":8

我有以下几点:

Class mLikes

    Public actors As IList(Of IList(Of String))

end Class

Class Player

    <JsonProperty(PropertyName:="id")>
    Public Id As Integer

    <JsonProperty(PropertyName:="name")>
    Public Name As String

    <JsonProperty(PropertyName:="likes")>
    Public Likes As mLikes

    <JsonProperty(PropertyName:="code")>
    Public Code As Integer

End Class

我正在使用 Newtonsoft.Json 进行反序列化:

Result = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Player)(jsonResponse)

如果我知道演员元素总是遵循相同的格式 -

Class Actor
  Public Name as String
  Public NumberOfMovies as Integer
  Public NumberOfAwards as Integer
  Public NumberOfTVshows as Integer
End Class 

有没有一种方法可以解析 JSON 响应,以便 Player.Likes.Actors 是 List(Of Actor) 而不是我现在拥有的 List(Of List(Of String))?

【问题讨论】:

实际上,Actors 看起来像 Object。每个演员项目都有一个相同的字符串,但是里面塞满了这 3 个整数。他们没有“命名”,所以问题是让他们映射到任何有意义的东西。如果你想要的只是名字,你可以解析它并把它们找出来 【参考方案1】:

您可以做的是创建一个JsonConverter,以正确的顺序将您的Actor 类序列化为IEnumerable&lt;object&gt;,然后在反序列化中使用LINQ to JSON 读取JSON,检查读取的令牌是一个数组,然后按等效顺序设置属性。

您可以为您的Actor 类硬编码它,但我认为创建一个通用转换器更有趣,该转换器使用 POCO 类型的属性顺序将不可枚举的 POCO 从和转换为 JSON 数组。可以使用&lt;JsonProperty(Order := NNN)&gt; 属性在您的类中指定此顺序。

因此,转换器:

Public Class ObjectToArrayConverter(Of T)
    Inherits JsonConverter

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

    Private Shared Function ShouldSkip(p As JsonProperty) As Boolean
        Return p.Ignored Or Not p.Readable Or Not p.Writable
    End Function

    Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
        If value Is Nothing Then
            writer.WriteNull()
        Else
            Dim type = value.GetType()
            Dim contract = TryCast(serializer.ContractResolver.ResolveContract(type), JsonObjectContract)
            If contract Is Nothing Then
                Throw New JsonSerializationException("invalid type " & type.FullName)
            End If
            Dim list = contract.Properties.Where(Function(p) Not ShouldSkip(p)).Select(Function(p) p.ValueProvider.GetValue(value))
            serializer.Serialize(writer, list)
        End If
    End Sub

    Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
        If reader.TokenType = JTokenType.Null Then
            Return Nothing
        End If
        Dim token = JArray.Load(reader)
        Dim contract = TryCast(serializer.ContractResolver.ResolveContract(objectType), JsonObjectContract)
        If contract Is Nothing Then
            Throw New JsonSerializationException("invalid type " & objectType.FullName)
        End If
        Dim value = If(existingValue, contract.DefaultCreator()())
        For Each pair In contract.Properties.Where(Function(p) Not ShouldSkip(p)).Zip(token, Function(p, v) New With  Key.Value = v, Key.Property = p )
            Dim propertyValue = pair.Value.ToObject(pair.Property.PropertyType, serializer)
            pair.Property.ValueProvider.SetValue(value, propertyValue)
        Next
        Return value
    End Function
End Class

还有你的班级:

<JsonConverter(GetType(ObjectToArrayConverter(Of Actor)))> _
Public Class Actor
    ' Use [JsonProperty(Order=x)] //http://www.newtonsoft.com/json/help/html/JsonPropertyOrder.htm to explicitly set the order of properties
    <JsonProperty(Order := 0)> _
    Public Property Name As String

    <JsonProperty(Order := 1)> _
    Public Property NumberOfMovies As Integer

    <JsonProperty(Order := 2)> _
    Public Property NumberOfAwards As Integer

    <JsonProperty(Order := 3)> _
    Public Property NumberOfTVshows As Integer
End Class

工作fiddle。

请注意,处理应用于属性的JsonConverter 属性的更新c# 版本可以在here 找到。

【讨论】:

这很好,非常感谢您的详细回复。我现在在上面实现您的代码的问题是以下行: Dim propertyValue = pair.Value.ToObject(pair.Property.PropertyType, serializer) in the converter.... 我收到错误:“重载解析失败,因为没有可访问的“ToObject”接受此数量的参数”。有什么想法吗? @Freemo - 我正在使用 JToken.ToObject(Type, JsonSerializer),它存在于当前版本的 Json.NET 中(并且似乎早在 Json.NET 4.5.11 中也存在)。您可以更新您的问题以显示您的代码,或将其上传到某处的 pastebin 吗?转换器在linked fiddle 中工作。 我更新到最新版本的 Json.NET 并且运行良好。你真是个天才!非常感谢 - 你拯救了我的周末。万事如意

以上是关于在 Visual Basic .NET 中反序列化 JSON的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio 中反序列化 JSON 文件时出错

如何在Visual Studio和CodeBlocks中反编译C++代码

在 .NET 中反序列化 Pokemon API

是否可以确定在 Json.Net 中反序列化了哪些属性? [复制]

如何在 asp.net 中反序列化 Json-Object

如何在 .NET 中反序列化为本地集合?