所以我正在做一个api调用,我需要使用JsonConvert.DeserializeObject把它转换成一个类。Json结构返回如下
{
"fcResponse": {
"responseData": {
"fcRequest": {
"mail": "Emails",
"outlookMail": "Outlook Emails",
(etc.)
}
}
}
}问题是,返回到"fcRequest“中的值会根据我发送的参数而变化。
到目前为止,类结构如下
public class GetSubModulesResponse : BaseResponse
{
[JsonProperty("fcResponse")]
public SubModuleResponse Response { get; set; }
}
public class SubModuleResponse
{
[JsonProperty("responseData")]
public SubModuleData Data { get; set; }
}
public class SubModuleData
{
[JsonProperty("fcRequest")]
public SubModuleFIMRequest RequestFIM { get; set; }
[JsonProperty("fcRequest")]
public SubModuleFSRequest RequestFS { get; set; }
}这是基本的调用结构
GetSubModulesResponse subModuleResponse = new GetSubModulesResponse();
var response = SubmitAPICall();
subModuleResponse = JsonConvert.DeserializeObject<GetSubModulesResponse>(response);现在我知道我显然不能在RequestFIM和RequestFS上都有相同的JsonProperty,但我试图做的是以某种方式找到一种方法来切换我应该基于变量使用这两个属性中的哪一个。
发布于 2020-07-09 05:28:39
一种选择是为元素使用自定义(反)序列化程序。这样,您仍然可以在大多数情况下从自动反序列化中获得最少的好处,并在需要的地方获得灵活性。我假设您使用的是Newtonsoft JSON / JSON.NET。
让我们首先为fcRequest元素引入一个基类。
public enum ResponseType
{
FIM, FS
}
public abstract class ResponseBase
{
[JsonIgnore]
public abstract ResponseType ResponseType { get; }
}通过在这里添加一个ResponseType,您可以简化代码的使用;如果您可以使用基于类型的模式匹配,那么您甚至可能不需要它。
我显然不知道您的域实体是什么,但为了便于讨论,SubModuleFIMRequest现在将包含邮件地址。此外,它还派生自所说的ResponseBase
public class SubModuleFIMRequest : ResponseBase
{
public override ResponseType ResponseType => ResponseType.FIM;
[JsonProperty("mail")]
public string Mail { get; set; }
[JsonProperty("outlookMail")]
public string OutlookMail { get; set; }
}接下来,您将实现一个JsonConverter<ResponseBase>;为了简单起见,它可以先将responseData内容反序列化为JObject。在这样做时,您将能够内省元素的属性,这反过来(希望)允许您提出一个启发式方法来确定元素的实际类型。
一旦知道了类型,就可以将JObject转换为具体的实例。下面是一个例子:
public class ResponseDataConverter : JsonConverter<ResponseBase>
{
/// <inheritdoc />
public override bool CanWrite => false;
/// <inheritdoc />
public override ResponseBase ReadJson(JsonReader reader, Type objectType, ResponseBase existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var jObject = serializer.Deserialize<JObject>(reader);
// Now, decide tye type by matching patterns.
if (jObject.TryGetValue("mail", out var mailToken))
{
return jObject.ToObject<SubModuleFIMRequest>();
}
// TODO: Add more types as needed
// If nothing matches, you may choose to throw an exception,
// return a catchall type (e.g. wrapping the JObject), or just
// return a default value as a last resort.
throw new JsonSerializationException();
}
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, ResponseBase value, JsonSerializer serializer) => throw new NotImplementedException();
}请注意,序列化程序不需要编写代码,所以我们只抛出了WriteJson。
剩下的就是用一个指向转换器类型的JsonConverter属性来注释SubModuleData的fcProperty属性:
public class SubModuleData
{
[JsonProperty("fcRequest")]
[JsonConverter(typeof(ResponseDataConverter))]
public ResponseBase FcRequest { get; set; }
}我希望这能让你开始。正如在其他评论和答案中所提到的:如果您可以在一开始就影响返回JSON的API,请尝试更改它。
发布于 2020-07-09 04:48:32
如果您可以控制返回的Json,我强烈建议您在每个对象自己的属性下返回每个对象,并将不需要的内容设置为null。
如果这不是一个选项,那么另一个可行的方法是将"fcRequest“反序列化为dynamic,然后尝试强制转换为可能的类型,或者基于另一个属性名称进行强制转换。这不是很干净。
另一种Json lib (Jil)中另一种有趣的方法是联合。"Jil has limited support for "unions" (fields on JSON objects that may contain one of several types), provided that they can be distiguished by their first character."
https://stackoverflow.com/questions/62798916
复制相似问题