如何将动态 json 属性 反序列化为对象?
How do I deserialize a dynamic json property to object?
我正在尝试将动态 JSON(从 API)反序列化为正确的对象,但是有些项目没有类型。在示例 JSON 中,"fulfillment" 属性 具有值 "F1" 和 "F2" 并且可能有更多(问题一)。其中,item properties有产品订单信息,但没有item type,以产品名称开头(即“03.64.0005_11_10”)可以有上千个选项(问题二)。
如何反序列化此 JSON 以填充正确的对象?我尝试了 RestCharp,Json.net,但我总是卡在无法动态读取和填充的产品 属性 上。
我尝试了以下答案,但没有成功:
How I deserialize a dynamic json property with RestSharp in C#?
Deserialize JSON into C# dynamic object?
你能帮帮我吗?
"billingAddress": {
"zip": "64001340",
"state": "PI",
"number": "3443",
"status": "ACTIVE",
"firstName": "Fulano",
"telephone": {
"type": "billing",
"number": "88112244"
},
"neighbourhood": "Centro"
},
"clientId": "cliente3",
"documents": [
{
"type": "cpf",
"number": "12345678901"
}
],
"fulfillments": {
"F1": {
"id": "F1",
"orderId": "4017116",
"channelId": "channel2",
"clientId": "cliente3",
"locationId": "708",
"shipment": {
"method": "Economica",
"carrierName": "Transportadora"
},
"status": "CANCELED",
"type": "SHIPMENT",
"enablePrePicking": false,
"items": {
"03.64.0005_11_10": {
"sku": "03.64.0005_11_10",
"quantity": 0,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 1,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
},
"18.06.0220_48_2": {
"sku": "18.06.0220_48_2",
"quantity": 0,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 1,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
}
}
},
"F2": {
"id": "F2",
"orderId": "4017116",
"channelId": "channel2",
"clientId": "cliente3",
"locationId": "003",
"operator": {
"id": "5188",
"name": "Loja da Vila"
},
"ownership": "oms",
"shipment": {
"method": "Economica",
"carrierName": "Transportadora"
},
"status": "SHIPPING_READY",
"type": "SHIPMENT",
"enablePrePicking": true,
"items": {
"18.04.1465_01_3": {
"sku": "18.04.1465_01_3",
"quantity": 1,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 0,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
},
"18.16.0630_13_10": {
"sku": "18.16.0630_13_10",
"quantity": 1,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 0,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
}
}
}
},
"createdAt": "2019-06-08T21:41:12.000Z",
"updatedAt": "2019-06-08T21:41:12.000Z"
}
To
public class BillingAddress
{
public string zip { get; set; }
public string state { get; set; }
public string number { get; set; }
public string status { get; set; }
public string firstName { get; set; }
public Telephone telephone { get; set; }
public string neighbourhood { get; set; }
}
public class Fulfillment
{
public string id { get; set; }
public string orderId { get; set; }
public string channelId { get; set; }
public string clientId { get; set; }
public string locationId { get; set; }
public Shipment shipment { get; set; }
public string status { get; set; }
public string type { get; set; }
public bool enablePrePicking { get; set; }
public List<Item> items { get; set; }
}
public class Item
{
public string sku { get; set; }
public int quantity { get; set; }
public string stockType { get; set; }
public int orderedQuantity { get; set; }
public int returnedQuantity { get; set; }
public int canceledQuantity { get; set; }
public string itemType { get; set; }
public bool presale { get; set; }
public bool enablePicking { get; set; }
}
是的,该结构确实不适合 JSON。看起来 fulfillments 属性 应该是这些对象的数组,而不是具有那些编号的属性。看起来这是从 EDI 文件或其他文件中 auto-generated 生成的,即使大多数好的转换工具都足够聪明,不会这样做。
选项 A:查看为您生成该文件的人是否可以更正他们的过程。
选项 B:如果这不可能,请将您的履行 属性 设为字典类型,其中履行是 class 您拥有的内部履行对象。然后将其反序列化 "properly" 并为您提供一个字典,您可以使用 "F1" 键引用直到 "FN" 但理想情况下,您会在使用字典时从字典中创建一个列表或数组。即使顺序很重要,您也始终可以使用 id 字段进行排序。
// Property on you deserialization object
public Dictionary<string, Fullfillment> fulfillmentDictionary {get; set;}
// Creating the list for easier use of the data
List<Fullfillment> fulfillments = fulfillmentDictionary.Values.ToList();
类似的逻辑将适用于您的项目列表。
如果问题只是键是动态的,而那些 dynamically-keyed 对象的结构是 well-defined,那么您可以使用 Dictionary<string, T>
(而不是 List<T>
) 来处理动态键。从你的样本 JSON 看来是这样的。因此,您需要根级别的 fulfillments
和 fulfillments
中的 items
的字典。您的 classes 应如下所示:
public class RootObject
{
public BillingAddress billingAddress { get; set; }
public string clientId { get; set; }
public List<Document> documents { get; set; }
public Dictionary<string, Fulfillment> fulfillments { get; set; }
public DateTime createdAt { get; set; }
public DateTime updatedAt { get; set; }
}
public class BillingAddress
{
public string zip { get; set; }
public string state { get; set; }
public string number { get; set; }
public string status { get; set; }
public string firstName { get; set; }
public Telephone telephone { get; set; }
public string neighbourhood { get; set; }
}
public class Telephone
{
public string type { get; set; }
public string number { get; set; }
}
public class Document
{
public string type { get; set; }
public string number { get; set; }
}
public class Fulfillment
{
public string id { get; set; }
public string orderId { get; set; }
public string channelId { get; set; }
public string clientId { get; set; }
public string locationId { get; set; }
public Operator @operator { get; set; }
public string ownership { get; set; }
public Shipment shipment { get; set; }
public string status { get; set; }
public string type { get; set; }
public bool enablePrePicking { get; set; }
public Dictionary<string, Item> items { get; set; }
}
public class Operator
{
public string id { get; set; }
public string name { get; set; }
}
public class Shipment
{
public string method { get; set; }
public string carrierName { get; set; }
}
public class Item
{
public string sku { get; set; }
public int quantity { get; set; }
public string stockType { get; set; }
public int orderedQuantity { get; set; }
public int returnedQuantity { get; set; }
public int canceledQuantity { get; set; }
public string itemType { get; set; }
public bool presale { get; set; }
public bool enablePicking { get; set; }
}
然后将JSON反序列化为RootObject
class:
var root = JsonConvert.DeserializeObject<RootObject>(json);
这是一个工作演示:https://dotnetfiddle.net/xReEQh
对于 JSON 具有动态键的消息(即消息之间的变化),您应该从解码为动态 C# 对象开始。一个解码(大多数 JSON 解析器支持它)你枚举每个动态 属性,然后将其值转换为 POCO,如 Fulfillment、Item 等(或者继续使用动态对象)。
这是一个适用于您的 JSON https://dotnetfiddle.net/U5NfzC
的示例
我正在尝试将动态 JSON(从 API)反序列化为正确的对象,但是有些项目没有类型。在示例 JSON 中,"fulfillment" 属性 具有值 "F1" 和 "F2" 并且可能有更多(问题一)。其中,item properties有产品订单信息,但没有item type,以产品名称开头(即“03.64.0005_11_10”)可以有上千个选项(问题二)。 如何反序列化此 JSON 以填充正确的对象?我尝试了 RestCharp,Json.net,但我总是卡在无法动态读取和填充的产品 属性 上。
我尝试了以下答案,但没有成功:
How I deserialize a dynamic json property with RestSharp in C#? Deserialize JSON into C# dynamic object?
你能帮帮我吗?
"billingAddress": {
"zip": "64001340",
"state": "PI",
"number": "3443",
"status": "ACTIVE",
"firstName": "Fulano",
"telephone": {
"type": "billing",
"number": "88112244"
},
"neighbourhood": "Centro"
},
"clientId": "cliente3",
"documents": [
{
"type": "cpf",
"number": "12345678901"
}
],
"fulfillments": {
"F1": {
"id": "F1",
"orderId": "4017116",
"channelId": "channel2",
"clientId": "cliente3",
"locationId": "708",
"shipment": {
"method": "Economica",
"carrierName": "Transportadora"
},
"status": "CANCELED",
"type": "SHIPMENT",
"enablePrePicking": false,
"items": {
"03.64.0005_11_10": {
"sku": "03.64.0005_11_10",
"quantity": 0,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 1,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
},
"18.06.0220_48_2": {
"sku": "18.06.0220_48_2",
"quantity": 0,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 1,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
}
}
},
"F2": {
"id": "F2",
"orderId": "4017116",
"channelId": "channel2",
"clientId": "cliente3",
"locationId": "003",
"operator": {
"id": "5188",
"name": "Loja da Vila"
},
"ownership": "oms",
"shipment": {
"method": "Economica",
"carrierName": "Transportadora"
},
"status": "SHIPPING_READY",
"type": "SHIPMENT",
"enablePrePicking": true,
"items": {
"18.04.1465_01_3": {
"sku": "18.04.1465_01_3",
"quantity": 1,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 0,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
},
"18.16.0630_13_10": {
"sku": "18.16.0630_13_10",
"quantity": 1,
"stockType": "PHYSICAL",
"orderedQuantity": 1,
"returnedQuantity": 0,
"canceledQuantity": 0,
"itemType": "OTHER",
"presale": false,
"enablePicking": true
}
}
}
},
"createdAt": "2019-06-08T21:41:12.000Z",
"updatedAt": "2019-06-08T21:41:12.000Z"
}
To
public class BillingAddress
{
public string zip { get; set; }
public string state { get; set; }
public string number { get; set; }
public string status { get; set; }
public string firstName { get; set; }
public Telephone telephone { get; set; }
public string neighbourhood { get; set; }
}
public class Fulfillment
{
public string id { get; set; }
public string orderId { get; set; }
public string channelId { get; set; }
public string clientId { get; set; }
public string locationId { get; set; }
public Shipment shipment { get; set; }
public string status { get; set; }
public string type { get; set; }
public bool enablePrePicking { get; set; }
public List<Item> items { get; set; }
}
public class Item
{
public string sku { get; set; }
public int quantity { get; set; }
public string stockType { get; set; }
public int orderedQuantity { get; set; }
public int returnedQuantity { get; set; }
public int canceledQuantity { get; set; }
public string itemType { get; set; }
public bool presale { get; set; }
public bool enablePicking { get; set; }
}
是的,该结构确实不适合 JSON。看起来 fulfillments 属性 应该是这些对象的数组,而不是具有那些编号的属性。看起来这是从 EDI 文件或其他文件中 auto-generated 生成的,即使大多数好的转换工具都足够聪明,不会这样做。
选项 A:查看为您生成该文件的人是否可以更正他们的过程。
选项 B:如果这不可能,请将您的履行 属性 设为字典类型,其中履行是 class 您拥有的内部履行对象。然后将其反序列化 "properly" 并为您提供一个字典,您可以使用 "F1" 键引用直到 "FN" 但理想情况下,您会在使用字典时从字典中创建一个列表或数组。即使顺序很重要,您也始终可以使用 id 字段进行排序。
// Property on you deserialization object
public Dictionary<string, Fullfillment> fulfillmentDictionary {get; set;}
// Creating the list for easier use of the data
List<Fullfillment> fulfillments = fulfillmentDictionary.Values.ToList();
类似的逻辑将适用于您的项目列表。
如果问题只是键是动态的,而那些 dynamically-keyed 对象的结构是 well-defined,那么您可以使用 Dictionary<string, T>
(而不是 List<T>
) 来处理动态键。从你的样本 JSON 看来是这样的。因此,您需要根级别的 fulfillments
和 fulfillments
中的 items
的字典。您的 classes 应如下所示:
public class RootObject
{
public BillingAddress billingAddress { get; set; }
public string clientId { get; set; }
public List<Document> documents { get; set; }
public Dictionary<string, Fulfillment> fulfillments { get; set; }
public DateTime createdAt { get; set; }
public DateTime updatedAt { get; set; }
}
public class BillingAddress
{
public string zip { get; set; }
public string state { get; set; }
public string number { get; set; }
public string status { get; set; }
public string firstName { get; set; }
public Telephone telephone { get; set; }
public string neighbourhood { get; set; }
}
public class Telephone
{
public string type { get; set; }
public string number { get; set; }
}
public class Document
{
public string type { get; set; }
public string number { get; set; }
}
public class Fulfillment
{
public string id { get; set; }
public string orderId { get; set; }
public string channelId { get; set; }
public string clientId { get; set; }
public string locationId { get; set; }
public Operator @operator { get; set; }
public string ownership { get; set; }
public Shipment shipment { get; set; }
public string status { get; set; }
public string type { get; set; }
public bool enablePrePicking { get; set; }
public Dictionary<string, Item> items { get; set; }
}
public class Operator
{
public string id { get; set; }
public string name { get; set; }
}
public class Shipment
{
public string method { get; set; }
public string carrierName { get; set; }
}
public class Item
{
public string sku { get; set; }
public int quantity { get; set; }
public string stockType { get; set; }
public int orderedQuantity { get; set; }
public int returnedQuantity { get; set; }
public int canceledQuantity { get; set; }
public string itemType { get; set; }
public bool presale { get; set; }
public bool enablePicking { get; set; }
}
然后将JSON反序列化为RootObject
class:
var root = JsonConvert.DeserializeObject<RootObject>(json);
这是一个工作演示:https://dotnetfiddle.net/xReEQh
对于 JSON 具有动态键的消息(即消息之间的变化),您应该从解码为动态 C# 对象开始。一个解码(大多数 JSON 解析器支持它)你枚举每个动态 属性,然后将其值转换为 POCO,如 Fulfillment、Item 等(或者继续使用动态对象)。
这是一个适用于您的 JSON https://dotnetfiddle.net/U5NfzC
的示例