vb.net 如何反序列化可以是数组或单个对象的 JSON
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28395700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to deserialize JSON which can be an array or a single object
提问by krazifan
I'm fairly new to using JSON.net and having trouble with some json I'm getting which sometime comes in as an array and sometimes as single object. Here is an example of what I'm seeing with the json
我对使用 JSON.net 还很陌生,并且在使用一些 json 时遇到了问题,有时以数组形式出现,有时以单个对象形式出现。这是我在 json 中看到的示例
One way it comes in ...
它进来的一种方式......
{
"Make": "Dodge",
"Model": "Charger",
"Lines": [
{
"line": "base",
"engine": "v6",
"color": "red"
},
{
"line": "R/T",
"engine": "v8",
"color": "black"
}
],
"Year": "2013"
}
Another way it could come in
它可以进入的另一种方式
{
"Make": "Dodge",
"Model": "Charger",
"Lines": {
"line": "base",
"engine": "v6",
"color": "red"
},
"Year": "2013"
}
Here is what I've been using for code which works on the first way and throws an exception in the second case. Been scouring the web for ways to implement this and am really stuck.
这是我一直在使用的代码,它以第一种方式工作并在第二种情况下引发异常。一直在网上搜索实现这一点的方法,我真的被困住了。
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
I'm guessing this will likely need a custom JsonConverter, but I'm a bit at a loss as to how to set that up.
我猜这可能需要一个自定义的 JsonConverter,但我对如何设置它有点不知所措。
回答by Brian Rogers
Here is how to get the SingleOrArrayConvertersolution in the linked duplicate questionworking for your use case.
以下是如何SingleOrArrayConverter在链接的重复问题中获得适用于您的用例的解决方案。
First, here is the VB-translated converter code. Take this and save it to a class file somewhere in your project. You can then easily reuse it for any future cases like this.
首先,这里是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
Now that you have this converter, any time you have a property that can be either a list or a single item, all you have to do is declare it as a list in your class and then annotate that list with a JsonConverterattribute such that it uses the SingleOrArrayConverterclass. In your case, that would look like this:
现在你有了这个转换器,任何时候你有一个可以是列表或单个项目的属性,你所要做的就是在你的类中将它声明为一个列表,然后用一个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
Then, just deserialize as you normally would, and it works as expected.
然后,像往常一样反序列化,它会按预期工作。
Dim car As jsonCar = JsonConvert.DeserializeObject(Of jsonCar)(json)
Here is a complete demonstration: https://dotnetfiddle.net/msYNeQ
这是一个完整的演示:https: //dotnetfiddle.net/msYNeQ
回答by krazifan
Thanks to both crowcoder & Kundan. I combined the two approaches and came up with something that works with both json inputs. Here is the final code.
感谢 crowcoder 和 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
Big thanks for the quick replies. This solved something I'd been spending a lot time off-and-on trying to figure out.
非常感谢您的快速回复。这解决了我一直花费大量时间试图弄清楚的问题。
回答by Kundan Singh Chouhan
You could achieve this to modify your jsonCarclass like below
你可以实现这个来修改你的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
And the code should be like below:
代码应该如下所示:
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
回答by Crowcoder
You can generically deserialize to Object and then inspect what you have. You can check for a JArray or JObject and act accordingly. You don't even need to deserialize into a specific type, you can work with the Dynamic objects but that may not be the best idea.
您可以一般地反序列化为 Object,然后检查您拥有的内容。您可以检查 JArray 或 JObject 并采取相应措施。您甚至不需要反序列化为特定类型,您可以使用 Dynamic 对象,但这可能不是最好的主意。
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

