C# 中反序列化可以是数组或单个对象的 json 对象的最佳方法
本文关键字:对象 单个 json 方法 最佳 数组 反序列化 | 更新日期: 2023-09-27 18:32:24
我们正在处理一个json API结果。只是为了让我们的生活变得困难,如果有多个对象,API 的提供者会将项目作为数组返回,如果只有一个对象,则作为单个对象返回。
例如
如果只有一个对象...
{
propertyA: {
first: "A",
second: "B"
}
}
或者,如果有多个:
{
propertyA: [
{
first: "A",
second: "B"
},
{
first: "A",
second: "B"
}
]
}
有没有人有处理这种情况的好方法?理想情况下,我们希望将两者序列化为
public class ApiResult{
public ApiItem[] PropertyA {get;set;}
}
这适用于第二个示例,但是在遇到第一个示例时,您会在System.Web.Extensions中出现类型为"System.MissingMethodException"的第一次机会异常.dll
其他信息:没有为"ApiItem[]"类型定义无参数构造函数。
我假设类定义如下
public class ApiResult
{
public ApiItem[] PropertyA { get; set; }
}
public class ApiItem
{
public string First { get; set; }
public string Second { get; set; }
}
您可以将 json 反序列化为动态变量,然后检查d.propertyA
的类型。如果是JArray
则propertyA
是一个数组,因此您可以将 json 反序列化为ApiResult
。如果是JObject
则propertyA
是单个对象,因此您需要手动构造ApiItem
并将其分配给ApiResult
PropertyA
。考虑以下方法
public ApiResult Deserialize(string json)
{
ApiResult result = new ApiResult();
dynamic d = JsonConvert.DeserializeObject(json);
if (d.propertyA.GetType() == typeof (Newtonsoft.Json.Linq.JObject))
{
// propertyA is a single object, construct ApiItem manually
ApiItem item = new ApiItem();
item.First = d.propertyA.first;
item.Second = d.propertyA.second;
// assign item to result.PropertyA[0]
result.PropertyA = new ApiItem[1];
result.PropertyA[0] = item;
}
else if (d.propertyA.GetType() == typeof (Newtonsoft.Json.Linq.JArray))
{
// propertyA is an array, deserialize json into ApiResult
result = JsonConvert.DeserializeObject<ApiResult>(json);
}
return result;
}
上面的代码将为两个 json 示例返回一个 ApiResult
实例。
工作演示:https://dotnetfiddle.net/wBQKrp
基于ekad的回答,我编写了代码:
- 更短:因为现在您没有 ApiItem 中的每个属性一一映射
- 在已经是数组的情况下可能会更快(通过不使用相同的 json 字符串输入调用两个版本的
JsonConvert.DeserializeObject
) - 明确说明如何引入其他属性
- 处理我们
propertyA
的未知类型的错误情况(可以是数组或对象)。
请注意,我调用 JObject.Parse
而不是 JsonConvert.DeserializeObject
,然后只ToObject<>
该特定情况下我需要的部分:
static ApiResult Deserialize(string json)
{
JObject j = JObject.Parse(json);
var propA = j["propertyA"];
switch (propA.Type.ToString())
{
case "Object":
return new ApiResult {
PropertyA = new[]{propA.ToObject<ApiItem>()},
SomethingElse = j["somethingElse"].ToObject<string>(),
};
case "Array":
return j.ToObject<ApiResult>();
default:
throw new Exception("Invalid json with propertyA of type " + propA.Type.ToString());
}
}
API 几乎相同,但我添加了SomethingElse
(用于展示如何使用此方法轻松处理其他属性):
public class ApiResult
{
public ApiItem[] PropertyA { get; set; }
public string SomethingElse { get; set; }
}
public class ApiItem
{
public string First { get; set; }
public string Second { get; set; }
}
工作演示:https://dotnetfiddle.net/VLbTMu
JSON# 有一个非常轻量级的工具,可以让你实现这一点。它将从较大的 JSON 对象中检索嵌入式 JSON,无论嵌入式 JSON 是对象还是数组:
const string schoolMetadata = @"{ "school": {...";
var jsonParser = new JsonObjectParser();
using (var stream =
new MemoryStream(Encoding.UTF8.GetBytes(schoolMetadata))) {
Json.Parse(_jsonParser, stream, "teachers");
}
在这里,我们从一个更大的"学校"对象中检索一个"教师"对象。
序列化/反序列化到/从 JSON 反序列化的最佳方法是 Json.NET
流行的 .NET 高性能 JSON 框架
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[] { "Small" };
string json = JsonConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "Expiry": "2008-12-28T00:00:00",
// "Sizes": [
// "Small"
// ]
//}
string json = @"{
'Name': 'Bad Boys',
'ReleaseDate': '1995-4-7T00:00:00',
'Genres': [
'Action',
'Comedy'
]
}";
Movie m = JsonConvert.DeserializeObject<Movie>(json);
string name = m.Name;
// Bad Boys