反序列化后代对象



我正在与一个我无法更改的基于 JSON 的 API 进行通信。 它始终返回一个 Response 对象,其中包含一个不同的 Result 对象。 通常它看起来像这样:

{ "ver": "2.0", "result": { "code": 0 } }

对于某些命令,Result 对象通过添加额外的属性来"增长":

{ "ver": "2.0", "result": { "code": 0, "hostName": "sample", "hostPort": 5000 } }

我使用 Newtonsoft 属性来定义对象,如下所示:

内部类 RpcResponse    {        [JsonProperty(PropertyName = "ver")]        公共字符串版本 { get; set; }        [JsonProperty(PropertyName = "result")]        公共 Rpc响应结果结果        {            获取;            设置;        }内部类 RpcResponseResult    {        [JsonProperty(PropertyName = "code")]        public int Code { get; set; }    }内部类 RpcExtendedResponseResult: RpcResponseResult    {        [JsonProperty(PropertyName = "hostName")]        公共字符串主机名 { get; set; }        [JsonProperty(PropertyName = "hostPort")]        public int HostPort { get; set; }

但是当响应对象反序列化时:

RpcResponse rspResponse = JsonConvert.DeserializeObject(rspString);

其 Result 属性始终显示为 RpcResponseResult 对象,即。JsonConvert 不知道将其构造为 RpcExtendedResponseResult 对象。

属性或转换器是否有某种方法可以恢复正确的后代对象? 我觉得我错过了一些明显的东西!

>这是因为对象的类型是RpcResponseResult。 反序列化程序只能反序列化以指定字段类型声明的字段。 它无法确定,因为一个类有"主机名",它现在是RpcExtendedResponseResult。

如果我这样做,如果需要,我可能会使结果成为具有默认值的所有可能字段的容器,然后您可以根据需要填充另一个对象。

internal class RpcResponseResultContainer
{
    [JsonProperty(PropertyName = "code")]
    public int Code { get; set; }
    [JsonProperty(PropertyName = "hostName")]
    private string mHostName = string.Empty;
    public string HostName 
    { 
       get { return mHostName;} 
       set { mHostName = value; }
    }
    [JsonProperty(PropertyName = "hostPort")]
    private int mHostPort = -1;
    public int HostPort 
    { 
       get { return mHostPort;} 
       set { mHostPort = value;}
    }

然后,如果你真的想按照你想要的方式获取你的对象,你可以在你的容器类中做这样的事情:

 public RpcResponseResult GetActualResponseType()
 {
     if(HostPort != -1 && !string.IsNullOrEmtpy(HostName))
     {
         return new RpcExtendedResponseResult() { Code = this.Code, HostName = this.HostName, HostPort = this.HostPort};
     }
     return new RpcResponseResult() { Code = this.Code };
 }

首先,感谢Matthew Frontino提供了我接受的唯一答案。

但是,我

选择不制作单个结果容器,所以这就是我最终所做的。

  1. 首先,我从这个页面开始:如何在 JSON.NET 中实现自定义 JsonConverter 以反序列化基类对象列表?
  2. 我使用了 Alain 提供的 JsonCreationConverter 版本。
  3. 我按照Dribbel的建议添加了CanWrite覆盖:

    public override bool CanWrite
    {
        get { return false; }
    }
    
  4. 我还在 JsonCreationConverter 中添加了自己的辅助函数:

    protected bool FieldExists(string fieldName, JObject jObject)    {
        return jObject[fieldName] != null;
    }
    
  5. 然后我创建了自己的转换器,如下所示:

    class RpcResponseResultConverter : JsonCreationConverter<RpcResponseResult>
    {
        protected override RpcResponseResult Create(Type objectType, JObject jObject)
        {
            // determine extended responses
            if (FieldExists("hostName", jObject) &&
                FieldExists("hostPort", jObject) )
            {
                return new RpcExtendedResponseResult();
            }
            //default
            return new RpcResponseResult();
        }
    }
    
  6. 然后我反序列化顶级类并提供要使用的任何转换器。 在这种情况下,我只提供了一个,这是针对有问题的嵌套类的:

    RpcResponse rspResponse = JsonConvert.DeserializeObject<RpcResponse>(
        rspString, 
        new JsonSerializerSettings {
            DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
            Converters = new List<JsonConverter>( new JsonConverter[] {
                    new RpcResponseResultConverter()
                    })
            });
    

笔记:

  • 转换器未显式处理的任何内容(例如顶级类)都使用 JsonConvert 中内置的默认转换器进行反序列化。
  • 仅当可以为每个后代类标识一组唯一的字段时,这才有效。

相关内容

  • 没有找到相关文章

最新更新