有没有一种方法可以使Json.Net反序列化为声明为“对象”的属性的具体类型

时间:2019-11-25 15:59:20

标签: c# json json.net

假设我有一个看起来像这样的JSON文档:

{
    "Id" : "233124",
    "RequestDate" : "2019-11-25T10:00:00"
    "RequestPayload" : {
        "Id" : "123abc",
        "Url" : "http://blah.example/api/action",
        "PostData" : "insert random post data here"
    }
}

我有几个看起来像这样的C#POCO:

public class RequestLog {
    public string Id { get; set; }
    public DateTime RequestDate { get; set; }
    public object RequestPayload { get; set; }
}

public class RequestPayload {
    public string Id { get; set; }
    public string Url { get; set; }
    public string PostData { get; set; }
}

是否有一种方法让Json.Net反序列化文档,使得RequestLog.RequestPayload属性的类型为RequestPayload,即使它被声明为object也是如此?目的是将其转换回RequestPayload以便对其进行操作,如下所示:

var result = JsonConvert.DeserializeObject<RequestLog>(json, ...);
var requestPayload = (RequestPayload)request.RequestPayload;
// do other stuff with requestPayload here

我无法更改RequestLog的声明,因为它位于我无法控制的NuGet包中。我研究过要创建一个自定义转换器,看来应该是可能的,但是我对如何实现它感到完全困惑。

3 个答案:

答案 0 :(得分:3)

您可以为RequestLog类使用自定义转换器:

public class RequestLogConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => objectType == typeof(RequestLog);

    public override bool CanWrite => false;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jObject = JObject.Load(reader);

        // Start by running the default serialisation
        var log = new RequestLog();
        serializer.Populate(jObject.CreateReader(), log);

        // Manually deserialize RequestPayload
        log.RequestPayload = jObject["RequestPayload"].ToObject<RequestPayload>();

        return log;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

可用于以下用途:

JsonConvert.DeserializeObject<RequestLog>(json, new JsonSerializerSettings
{
    Converters = new JsonConverter[] { new RequestLogConverter() }
});

答案 1 :(得分:1)

如果必须将RequestPayload的{​​{1}}属性声明为RequestLog,并且不需要此代码可重复使用,则可以强制使用此代码。

object

答案 2 :(得分:-1)

在您的RequestLog类中,

更改:

public object RequestPayload { get; set; }

收件人:

public RequestPayload RequestPayload { get; set; }

然后您可以在反序列化之后使用它,而不必强制转换它:

var result = JsonConvert.DeserializeObject<RequestLog>(json, ...);
var requestPayload = result.RequestPayload;
// do other stuff with requestPayload here