我正在从 Web 服务器检索 JSON 响应,并为所有属性创建了强类型类,没有任何问题,除了一个可以是单个字符串值或嵌套数组的属性之外。
JSON 示例:
"meta_data": [
{
"id": 12772,
"key": "_shipping_phone",
"value": ""
},
{
"id": 12786,
"key": "status",
"value": "completed"
},
{
"id": 12788,
"key": "Payment type",
"value": "instant"
},
{
"id": 12796,
"key": "_transaction_fee",
"value": "0.39"
},
{
"id": 12806,
"key": "connect_destination_normalized",
"value": "1"
},
{
"id": 12807,
"key": "wc_connect_labels",
"value": [
{
"label_id": 1633947,
"tracking": "9400***************",
"refundable_amount": 3.930000000000000159872115546022541821002960205078125,
"created": 1589499950667,
"carrier_id": "usps",
"service_name": "USPS - First Class Mail",
"status": "PURCHASED",
"package_name": "Bubble Mailer",
"product_names": [
"Peace Love And Wine Sub Tshirt"
],
"receipt_item_id": 60476008,
"created_date": 1589499955000,
"main_receipt_id": 46201718,
"rate": 3.930000000000000159872115546022541821002960205078125,
"currency": "USD",
"expiry_date": 1605051955000,
"label_cached": 1589499962000
},
{
"label_id": 1633942,
"tracking": null,
"refundable_amount": 0,
"created": 1589499912741,
"carrier_id": null,
"service_name": "USPS - First Class Mail",
"status": "PURCHASE_ERROR",
"package_name": "Bubble Mailer",
"product_names": [
"Peace Love And Wine Sub Tshirt"
],
"receipt_item_id": -1,
"created_date": 1589499912000,
"error": "The transaction was declined."
},
{
"label_id": 1633913,
"tracking": null,
"refundable_amount": 0,
"created": 1589499712367,
"carrier_id": null,
"service_name": "USPS - First Class Mail",
"status": "PURCHASE_ERROR",
"package_name": "Bubble Mailer",
"product_names": [
"Peace Love And Wine Sub Tshirt"
],
"receipt_item_id": -1,
"created_date": 1589499712000,
"error": "The transaction was declined."
}
]
}
如您所见,value
键是一个普通的字符串值(或空白字符串)。然而,正如最终条目所示,它还可以更多。
这是我的强类型类:
Public Class Meta_Data
Public Property id As Integer
Public Property key As String
'<JsonConverter(GetType(SingleOrArrayConverter(Of Values())))>
Public Property value As Values()
End Class
Public Class Values
Public Property label_id As Integer
Public Property tracking As String
Public Property refundable_amount As String
Public Property created As String
Public Property carrier_id As String
Public Property service_name As String
Public Property status As String
Public Property package_name As String
Public Property product_names As String()
Public Property receipt_item_id As String
Public Property created_date As String
Public Property [error] As String
Public Property main_receipt_id As String
Public Property rate As String
Public Property currency As String
Public Property expiry_date As String
Public Property label_cached As String
End Class
我在互联网上搜索了解决方案,但未能找到一个。我尝试了找到的不同转换器示例,但没有一个起作用,因为它们仍然尝试通过 Values
类传递单个字符串。
这是我的反序列化调用:
Dim info As Order = JsonConvert.DeserializeObject(Of Order)(responseFromServer)
我还有多个其他类,我不打算占用空间来显示它们,但根类称为 Order
。
基本上,有没有办法在处理反序列化时检查 value
以查看它是否是字符串并阻止它通过 Values
类进行处理?
最佳答案
由于您希望以不同于数组的方式处理单个字符串值,因此您需要更改模型以使其具有多态性。也就是说,创建一个基类,其中包含所有 meta_data
项共有的 id
和 key
属性,然后创建子类来表示字符串和数组变种。所以,像这样:
Public Class Order
Public Property meta_data As List(Of BaseMetaData)
End Class
<JsonConverter(GetType(MetaDataConverter))>
Public Class BaseMetaData
Public Property id As Integer
Public Property key As String
End Class
Public Class StringMetaData
Inherits BaseMetaData
Public Property value As String
End Class
Public Class ComplexMetaData
Inherits BaseMetaData
Public Property value As List(Of Values)
End Class
Public Class Values
Public Property label_id As Integer
Public Property tracking As String
Public Property refundable_amount As String
Public Property created As String
Public Property carrier_id As String
Public Property service_name As String
Public Property status As String
Public Property package_name As String
Public Property product_names As String()
Public Property receipt_item_id As String
Public Property created_date As String
Public Property [error] As String
Public Property main_receipt_id As String
Public Property rate As String
Public Property currency As String
Public Property expiry_date As String
Public Property label_cached As String
End Class
然后您可以为基类创建一个自定义 JsonConverter
来检测值类型并创建正确的子类:
Public Class MetaDataConverter
Inherits JsonConverter
Public Overrides Function CanConvert(objectType As Type) As Boolean
Return GetType(BaseMetaData).IsAssignableFrom(objectType)
End Function
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
Dim jo As JObject = JObject.Load(reader)
Dim val As JToken = jo("value")
Dim meta As BaseMetaData
If val.Type = JTokenType.Array Then
meta = New ComplexMetaData()
Else
meta = New StringMetaData()
End If
serializer.Populate(jo.CreateReader(), meta)
Return meta
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
最后一部分是使用 JsonConverter
属性标记 BaseMetaData
,我已经在上面的模型声明中完成了该操作。然后,您可以像平常一样反序列化,一切都应该“正常工作”。
这是一个工作演示:https://dotnetfiddle.net/3uYXKu
关于json - 使用 Newtonsoft 反序列化 JSON 属性(当它可以是单个字符串或 JARRAY 时),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61905410/