使用嵌入类型反序列化JSON

时间:2017-01-16 03:35:34

标签: .net vb.net json.net

我有以下JSON:

{
    "type": "champion",
    "version": "6.24.1",
    "data": {
        "Jax": {
            "id": 24,
            "key": "Jax",
            "name": "Jax",
            "title": "Grandmaster at Arms",
            "image": {
                "full": "Jax.png",
                "sprite": "champion1.png",
                "group": "champion",
                "x": 48,
                "y": 48,
                "w": 48,
                "h": 48
            }
        },
        "Sona": {
            "id": 37,
            "key": "Sona",
            "name": "Sona",
            "title": "Maven of the Strings",
            "image": {
                "full": "Sona.png",
                "sprite": "champion3.png",
                "group": "champion",
                "x": 288,
                "y": 0,
                "w": 48,
                "h": 48
            }
        }
    }
}

RiotRequestManager收集字符串。我希望能够从LeagueObjectManager类中访问“full”和“sprite”的图像字符串。我得到了一个名单列表并提供了方法,我希望能够使用LeagueObject中的名称来提取图像。我在列表中单击他们的名称并尝试返回图像完整字符串。我尝试的所有内容都提供了空响应。

我有以下课程:

Imports Newtonsoft.Json
Public Class LeagueObjectManager
    Private rrm As New RiotRequestManager
    Private lc As LeagueObjectContainer
    Private count As Integer

    Public Sub New(ByVal strRegion As String, ByVal strMode As String)
        lc = JsonConvert.DeserializeObject(Of LeagueObjectContainer)(rrm.returnLeagueItems(strRegion, strMode))
        count = lc.data.Count()
    End Sub

    Public Function returnNames() As String()
        Dim strReturn(count - 1) As String
        Dim errorCount As Integer = 0
        Dim counter As Integer = 0
        For i = 0 To count - 1
            If Not (lc.data.ElementAt(i).Value.name = "error") Then
                strReturn(counter) = lc.data.ElementAt(i).Value.name
                counter += 1
            Else
                errorCount += 1
                ReDim Preserve strReturn(count - 1 - errorCount)
            End If
        Next
        Return strReturn
    End Function
End Class

Public Class LeagueObjectContainer
    Public Property type As String
    Public Property version As String
    Public Property data As SortedDictionary(Of String, LeagueObject)
End Class

Public Class LeagueObject
    Public Property id As Integer
    Public Property key As String
    Public Property name As String = "error"
    Public Property title As String
    Public Property image As SortedDictionary(Of String, LeagueImage)
    Public Property group As String
    Public Property tags As String()
    Public Property enemytips As String
    Public Property allytips As String
End Class

Public Class LeagueImage
    Public Property full As String
    Public Property sprite As String
End Class

2 个答案:

答案 0 :(得分:3)

两个问题:

  1. 您的JSON语法无效。你错过了最后的结束括号。
  2. 您的类层次结构与JSON结构不匹配。
  3. 如果您的JSON结构已修复且无法更改,则可以通过在Visual Studio中选择Edit/Paste Special/Paste JSON as Classes来获取关联的类层次结构。

答案 1 :(得分:3)

您可以使用多种效率来应对所拥有的内容。主要是,您不需要另一个类充当管理器:您要添加的任何方法或其他属性都可以添加到现有类中。使用稍微更惯用的名称:

Public Class DataItem
    Public Property id As Integer
    Public Property key As String
    Public Property name As String = ""
    Public Property title As String
    Public Property image As ImageInfo

    Public Overrides Function ToString() As String
        Return name
    End Function
End Class

Public Class ImageInfo
    Public Property full As String
    Public Property sprite As String
    Public Property group As String
    Public Property x As Integer
    Public Property y As Integer
    Public Property w As Integer
    Public Property h As Integer
End Class

即使您对它们不感兴趣,我也会将所有图像属性保留在那里。然后容器类可以是容器和管理器类的混合:

Public Class LeagueManager
    Public Property type As String
    Public Property version As String
    Public Property data As Dictionary(Of String, DataItem)

    Public Sub New()

    End Sub

    ' could/should be As IEnumerable(Of String)
    Public Function GetPlayerNames() As String()

        ' enumerate Values collection of dictionary,
        '  filter out those with no name 
        '  select/pick/use the DataItem.name 
        '  put them in alpha order
        '  convert from IEnumerable to an array
        Dim names = data.Values.AsEnumerable().
                        Where(Function(j) String.IsNullOrEmpty(j.name) = False).
                        Select(Function(q) q.name).
                        OrderBy(Function(k) k).
                        ToArray()
        Return names
    End Function

    Public Function GetPlayer(name As String) As DataItem
        ' first first DataItem where the names match
        Return data.Values.
            FirstOrDefault(Function(q) String.Compare(name, q.name, StringComparison.InvariantCultureIgnoreCase) = 0)
    End Function

    Public Function GetPlayers() As DataItem()
        Return data.Values.AsEnumerable().Cast(Of DataItem).ToArray()
    End Function
End Class
  1. 你不必将它们结合起来:它是一个选择。 json相关类越复杂,我就越不可能这样做。
  2. 简化了获取播放器名称的代码
  3. 有多种方法可以访问数据项
  4. 我不知道某些道具来自allytips。我猜你试图用1个以上的json?如果是这样,我可能不会合并经理和容器。
  5. 使用普通Dictionary而不是SortedDictionary。以任何形式或顺序从Dictionary获得您想要的任何内容都很容易。
  6. ToString()上的DataItem覆盖在调试时非常有用。
  7. 如果你将管理器和容器结合起来,不要从构造函数中反序列化,我认为当JSON.NET创建另一个用于反序列化的循环时,你会进入无限循环。显式Load方法允许您(重新)加载其他参数/​​区域等的数据。

    GetPlayer(string)方法返回单个DataItem,其中名称匹配(不区分大小写)。这不依赖于Dictionary密钥,而是隐藏了实现的DataItems中的实际名称,但如果可以删除/删除项目,则可以返回Nothing

    Dim JaxData = myData.GetPlayer("jax")
    If JaxData IsNot Nothing Then
        ...
    End If
    

    这将提供另一种使用从GetPlayerNames()返回的名称来迭代集合的方法。您可以添加CountHasPlayer以及您需要的任何其他属性和方法。至于图像,它只是DataItem上的另一个属性:

    Dim jstr = ...
    
    Dim leagueData = JsonConvert.DeserializeObject(Of LeagueManager)(jstr)
    
    ' get array of names
    Dim names = leagueData.GetPlayerNames()
    
    Dim di As DataItem
    For Each s As String In names
        ' get DataItem object for player named in 's'
        di = leagueData.GetPlayer(s)
        If di IsNot Nothing Then
            Console.WriteLine("{0} aka '{1}' uses image: '{2}'", di.name,
                              di.title, di.image.sprite)
        Else
            ' very unlikely:
            Console.WriteLine("Cannot find {0}", s)
        End If
    
    Next
    

    结果:

      

    贾克斯
      索娜
      Jax aka' Grandmaster at Arms'使用image:' champion1.png'
      Sona aka' Maven of the Strings'使用image:' champion3.png'