[英]How can I deserialize JSON when the object type is not known beforehand?
So I have an API and front-end that I am developing, and I need a way to deserialize JSON when one of the values could be a List of multiple different types.所以我有一个 API 和我正在开发的前端,我需要一种方法来反序列化 JSON 当其中一个值可能是多个不同类型的列表时。 Currently I'm deserializing it into a List<dynamic>
but that's a huge pain to work with in my context.目前我正在将其反序列化为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; }
}
Sample JSON样品 JSON
{
"status": "ok",
"code": 200,
"error": null,
"guid": "1234",
"results": [
{
"SamAccountName": "dizbuster",
"CN": "Buster, Diz",
"EmailAddress": "dizbuster@whatever.com",
}
]
}
In the above example JSON, results should be deserialized into type List<ClassA>
for example.在上面的示例 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",
}
]
}
Where as in this sample, results should be deserialized into List<ClassB>
.在此示例中,结果应反序列化为List<ClassB>
。
Some of the field names may show up in different types, but some are not.一些字段名称可能会以不同的类型显示,但有些则不会。 Functionally they are two different types representing the outputs from two separate API calls, so I'd like to have it deserialize into specific object types as opposed to using dynamic
or a monolithic object that contains every possible field.从功能上讲,它们是两种不同的类型,表示来自两个单独的 API 调用的输出,所以我想让它反序列化为特定的 object 类型,而不是使用包含每个可能字段的dynamic
或单片 ZA8CFDE6331BD59EB2AC96F8911C4B6666。
Currently I'm taking the List<dynamic>
and serializing it back into a temporary JSON string, then deserializing it again into the List<ClassA>
or whatever.目前,我正在将List<dynamic>
序列化回临时 JSON 字符串,然后将其再次反序列化为List<ClassA>
或其他任何内容。 This seems like a bad way to do it, and is cumbersome to work with.这似乎是一种不好的方法,并且使用起来很麻烦。
Is there a better way to structure this or to handle the serialization/deserialization?有没有更好的方法来构造它或处理序列化/反序列化? I have full control over both ends so it's not too difficult for me to alter the JSON as well if needed.我可以完全控制两端,因此如果需要,我也可以轻松更改 JSON。 Also, I know that a particular API call will return JSON that looks like this, while another API call will return JSON that looks like that. Also, I know that a particular API call will return JSON that looks like this, while another API call will return JSON that looks like that. Each case should result in a differently typed list每个案例都应该产生一个不同类型的列表
Since you know in advance what type of data is being returned in "results"
for each API call, you can make your WorkbenchAPI
class generic:由于您事先知道每个 API 调用的"results"
中返回的数据类型,您可以使WorkbenchAPI
class 通用:
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>();
}
Notes:笔记:
I extracted the common properties into an abstract base class to allow them to be accessed by pre-existing non-generic code that does not care about the specific type of result.我将公共属性提取到抽象基础 class 中,以允许通过不关心特定结果类型的预先存在的非泛型代码访问它们。
I also added a IReadOnlyCollection<dynamic> results
to the base class to ease integration with pre-existing code, eg:我还在基础 class 中添加了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. // Eg: accessing root properties like guid or getting the result count. WorkbenchAPI baseRoot = root; var count = baseRoot.results.Count; var guid = baseRoot.guid;
However, adding access to the results as a non-generic read-only collection of dynamic
objects is optional, and could be removed if your legacy code can be rewritten to be generic.但是,作为dynamic
对象的非泛型只读集合添加对结果的访问是可选的,如果您的旧代码可以重写为泛型,则可以将其删除。
Demo fiddle here: https://dotnetfiddle.net/lbTs1z演示小提琴在这里: https://dotnetfiddle.net/lbTs1z
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.