我们正在处理json API结果。只是为了让我们的生活变得困难,API的提供者如果有多个对象则将项目作为数组返回,或者如果只有一个对象则作为单个对象返回。
e.g。
如果只有一个对象......
{
propertyA: {
first: "A",
second: "B"
}
}
或者如果有多个:
{
propertyA: [
{
first: "A",
second: "B"
},
{
first: "A",
second: "B"
}
]
}
有没有人有办法处理这种情况? 理想情况下,我们希望将两者序列化为
public class ApiResult{
public ApiItem[] PropertyA {get;set;}
}
这适用于第二个示例,但是在遇到第一个示例时,您会遇到类型为' System.MissingMethodException'的第一次机会异常。发生在System.Web.Extensions.dll
中附加信息:没有为' ApiItem []'的类型定义无参数构造函数。
答案 0 :(得分:2)
我假设类定义如下
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
并将其分配给PropertyA
ApiResult
。考虑下面的方法
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
的实例。
答案 1 :(得分:0)
向/从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
答案 2 :(得分:0)
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");
}
在这里,我们从较大的“学校”对象中检索“教师”对象。
答案 3 :(得分:0)
在ekad's answer的基础上,我使代码更易于维护(因为现在您没有在ApiItem中指定每个属性),并且更易于引入其他属性(如果已经存在并且数组):
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());
}
}
对于这些示例类(我刚刚添加了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