问题描述
我从 web hook 中获取 JSON,其中对象的类型被烘焙到 JSON 本身中,有点像这样:
类型为“a”的数据示例:
{
"type": "a","name": "object name","a_data": "something specific to type a"
}
以及类型为“b”的数据示例:
{
"type": "b","name": "another object name","b_data": {
"b_field1": "Something specific to type b","b_field2": "Something else specific to type b"
}
我保证每个负载都具有 type
和 name
属性。 type
"a" 的所有负载都将另外有一个 a_data
属性,type
b 的所有负载将另外有一个 b_data
属性,它本身由属性 {{ 1}} 和 b_field1
。
(当然,为了说明这个问题,这非常简单——实际用例有更长、更复杂的 json 和更多类型)
我想反序列化为 C# 类,建模一个基类(至少包含 b_field2
属性,可能还有 name
属性)和两个派生类,一个用于序列化的对象在 type
"a" json 中,还有一个用于在 type
"b" json 中序列化的对象。
我想像这样定义 C# 类:
type
鉴于我不知道有效负载何时传入它是什么类型,我需要根据传入类型有条件地反序列化。但在我反序列化之前,我不“知道”那是什么类型。我很确定以下方法可行,但这不是一个特别好的解决方案,因为这意味着我需要反序列化两次:
public class Base
{
public string type { get; set; }
public string name { get; set; }
}
public class DeriviedA: Base
{
public string a_data { get; set; }
}
public class DervivedB : Base
{
public class DataB
{
public string b_field1 { get; set; }
public string b_field2 { get; set; }
}
public DataB b_data { get; set; }
}
现在除了需要进行不优雅的双重反序列化之外,请注意我无法将 public static Base Deserialize(string incomingJson)
{
Base tmp = JsonConvert.DeserializeObject<Base>(incomingJson);
switch (tmp.type)
{
case "a":
return JsonConvert.DeserializeObject<DerivedA>(incomingJson);
case "b":
return JsonConvert.DeserializeObject<DerivedB>(incomingJson);
default:
throw new InvalidOperationException($"unable to deserialize payload of type {tmp.type}");
}
}
类标记为 Base
,即使我从不想要 {{1 }} 类本身。
无论如何,我对这样做的想法、策略或最佳实践很好奇。我的偏好是使用 Newtonsoft 进行反序列化,但这不是要求。
解决方法
在使用序列化器之前,只需使用非反序列化 JSON 读取器来嗅探类型。
Newtonsoft 有一个非常简单的方法来做到这一点:
dynamic message = JObject.Parse(json);
string type = message.type;
https://www.newtonsoft.com/json/help/html/QueryJsonDynamic.htm