所以我有一个正在开发的API和前端,当值之一可能是多种不同类型的列表时,我需要一种反序列化JSON的方法。目前,我正在将其反序列化为List<dynamic>
,但是在我的上下文中使用它是一个巨大的痛苦。
public class WorkbenchAPI
{
public string status { get; set; }
public HttpStatusCode code { get; set; }
public string error { get; set; }
public string guid { get; set; }
public List<dynamic> results { get; set; }
}
示例JSON
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"SamAccountName": "dizbuster",
"CN": "Buster, Diz",
"EmailAddress": "dizbuster@whatever.com",
}
]
}
例如,在上述示例JSON中,结果应反序列化为类型List<ClassA>
。
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"data": "127.0.0.1",
"owner": "dizbuster",
"email": "dizbuster@whatever.com",
},
{
"data": "192.168.0.1",
"owner": "dizbuster",
"email": "dizbuster@whatever.com",
}
]
}
与本示例一样,结果应反序列化为List<ClassB>
。
某些字段名称可能以不同的类型显示,但有些则没有。从功能上讲,它们是两种不同的类型,分别代表两个单独的API调用的输出,因此我希望将其反序列化为特定的对象类型,而不是使用dynamic
或包含每个可能字段的整体对象。
当前,我正在使用List<dynamic>
并将其序列化回临时JSON字符串,然后再次将其反序列化为List<ClassA>
或其他任何形式。这似乎是一种不好的方法,并且使用起来很麻烦。
是否有更好的方法来结构化或处理序列化/反序列化?我对两端都有完全的控制权,因此如果需要,对我来说更改JSON也并不困难。另外,我知道一个特定的API调用将返回看起来像这样的JSON,而另一个API调用将返回看起来像这样的JSON。每种情况下都应产生不同类型的列表
答案 0 :(得分:1)
由于您事先知道"results"
会为每个API调用返回哪种类型的数据,因此可以使WorkbenchAPI
类通用:
public abstract class WorkbenchAPI
{
protected abstract IReadOnlyCollection<dynamic> GetResults();
public string status { get; set; }
public HttpStatusCode code { get; set; }
public string error { get; set; }
public string guid { get; set; }
public IReadOnlyCollection<dynamic> results => GetResults();
}
public class WorkbenchAPI<T> : WorkbenchAPI where T : class
{
protected override IReadOnlyCollection<dynamic> GetResults() => results;
public new List<T> results { get; set; } = new List<T>();
}
注意:
我将通用属性提取到抽象的基类中,以允许通过预先存在的,不关心特定结果类型的非通用代码来访问它们。
我还向基类添加了IReadOnlyCollection<dynamic> results
,以简化与现有代码的集成,例如:
// Deserialize to the concrete, known type
var root = JsonConvert.DeserializeObject<WorkbenchAPI<ClassA>>(json);
// Access the results in a type-safe manner:
var accounts = root.results.Select(r => r.SamAccountName).ToList();
// Upcast to the base class in code where we don't need to know about the specific result type.
// E.g.: accessing root properties like guid or getting the result count.
WorkbenchAPI baseRoot = root;
var count = baseRoot.results.Count;
var guid = baseRoot.guid;
但是,添加对结果的访问权限作为dynamic
对象的非通用只读集合是可选的,如果可以将旧代码重写为通用代码,则可以将其删除。
演示在这里摆弄:https://dotnetfiddle.net/lbTs1z