1

所以我正在做一个 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,但我想要做的是以某种方式找到一种方法来切换我应该根据变量使用这两个属性中的哪一个。

4

2 回答 2

0

如果您可以控制返回的 Json,我强烈建议您在其自己的属性下返回每个对象,并将不需要的任何内容设置为 null。

如果这不是一个选项,另一件可以工作的事情是将“fcRequest”反序列化为动态,然后尝试转换为它可能是的类型或基于另一个属性名称进行转换。那不是很干净。

另一个 Json lib ( Jil ) 中的另一个有趣的方法是 Unions。 “Jil 对“联合”(JSON 对象上可能包含几种类型之一的字段)的支持有限,前提是它们可以通过它们的第一个字符来区分。”

于 2020-07-08T20:48:31.680 回答
0

一种选择是为元素使用自定义(反)序列化程序。这样,您仍然可以在大多数情况下从自动反序列化中受益最少,并在需要的地方获得灵活性。我假设您使用的是 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.

剩下的就是用指向转换器类型的属性来注释SubModuleData'属性:fcPropertyJsonConverter

public class SubModuleData
{
    [JsonProperty("fcRequest")]
    [JsonConverter(typeof(ResponseDataConverter))]
    public ResponseBase FcRequest { get; set; }
}

我希望这能让你开始。正如其他评论和答案中提到的那样:如果您可以首先影响返回 JSON 的 API,请尝试更改它。

于 2020-07-08T21:28:39.287 回答