问题
Wondering if you could help me create a VB.Net class into which I can deserialize the following JSON response:
{
"id":86,
"name":"Tom",
"likes":
{
"actors":[
["Clooney",2,30,4],
["Hanks",104,15,1]
]
},
"code":8
}
I have the following:
Class mLikes
Public actors As IList(Of IList(Of String))
end Class
and
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
I am using Newtonsoft.Json to deserialize:
Result = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Player)(jsonResponse)
If I know that the actors elements always follow the same format -
Class Actor
Public Name as String
Public NumberOfMovies as Integer
Public NumberOfAwards as Integer
Public NumberOfTVshows as Integer
End Class
Is there a way I can parse the JSON response so that Player.Likes.Actors is a List(Of Actor) instead of a List(Of List(Of String)) which is what I have now?
回答1:
What you can do is to create a JsonConverter that serializes your Actor
class as an IEnumerable<object>
in the correct order, then in deserialization reads the JSON using LINQ to JSON, checks that the token read is an array, then sets the properties in the equivalent order.
You could hardcode this for your Actor
class, but I think it's more interesting to create a generic converter that converts non-enumerable POCO from and to a JSON array using the POCO type's property order. This order can be specified in your class using the <JsonProperty(Order := NNN)> attribute.
Thus, the converter:
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
And your 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
Working fiddle.
Note an updated c# version that handles JsonConverter
attributes applied to properties can be found here.
来源:https://stackoverflow.com/questions/31905958/deserializing-json-in-visual-basic-net