分两步反序列化Json



我想分两步反序列化我的Json,因为我必须阅读第一部分才能知道它是什么类型的Object。

我必须阅读这种Json:

{"header":3,"data":{"result":"myResult"}}

它的可读性更像

{
    "header":3,
    "data":{
        "result":"myResult"
    }
}

我在一个名为ProtocolHeader:的类中反序列化这个Json

public class ProtocolHeader
{
    [JsonProperty("header")]
    public int Header { get; set; }
    [JsonProperty("data")]
    public string Data { get; set; }
}

要做到这一点,我使用这个代码:

JsonConvert.DeserializeObject<ProtocolHeader>(Json)

根据Header的值,我将选择不同的类来反序列化文件的末尾。

例如,我可以有另一个类

public class ProtocolResult
{
    [JsonProperty("result")]
    public string Result{ get; set; }
}

或者类似

public class ProtocolError
{
    [JsonProperty("errorNumber")]
    public int ErrorNumber{ get; set; }
    [JsonProperty("additionalInformation")]
    public string AdditionalInformation{ get; set; }
}

你有分两步分离反序列化对象的想法吗?

感谢

您可以创建3个类。一个具有所有字段的公共类(非基类),然后是ProtocolResult&ProtocolError

然后实现对每个的隐式强制转换。你也可以在你的公共类上放一个IsError getter来决定如何使用它

您可以使用读取器只读取您需要的时间,然后跳过读取器进行真正的反序列化。

可能不会比先反序列化为简单对象,然后再反序列化为真实对象好多少,但这是一种替代方案。

你也许可以稍微调整一下。

string json = @"{""header"":3,""data"":{""result"":""myResult""}}";
using (var stringReader = new StringReader(json))
{
    using (var jsonReader = new JsonTextReader(stringReader))
    {
        while (jsonReader.Read())
        {
            if (jsonReader.TokenType == JsonToken.PropertyName 
                && jsonReader.Value != null
                && jsonReader.Value.ToString() == "header")
            {
                jsonReader.Read();
                int header = Convert.ToInt32(jsonReader.Value);
                switch (header)
                {
                    case 1:
                        // Deserialize as type 1
                        break;
                    case 2:
                        // Deserialize as type 2
                        break;
                    case 3:
                        // Deserialize as type 3
                        break;
                }
                break;
            }
        }
    }
}

选项1:不为data类使用抽象基类

我发现最简单的方法如下:

  1. 使用JToken作为未知对象的字段类型来声明类。

    [JsonObject(MemberSerialization.OptIn)]
    public class ProtocolHeader
    {
        [JsonProperty("header")]
        private int _header;
        [JsonProperty("data")]
        private JToken _data;
    }
    
  2. 在属性中公开专用数据。

    public ProtocolResult Result
    {
        get
        {
            if (_data == null || _header != ResultHeaderValue)
                return null;
            return _data.ToObject<ProtocolResult>();
        }
    }
    public ProtocolError Error
    {
        get
        {
            if (_data == null || _header != ErrorHeaderValue)
                return null;
            return _data.ToObject<ProtocolError>();
        }
    }
    

选项2:为data类使用抽象基类

另一种选择是为各种数据类型创建一个抽象基类,并在抽象基类中创建一个静态方法来执行类型选择和正确的反序列化。当类型信息包含在对象本身中时(例如,如果headerdata对象内部的属性),这尤其有用。

  1. LoadBalancerConfiguration<T>._healthMonitor字段的类型为JObject,但同一类中的HealthMonitor属性返回一个HealthMonitor对象
  2. HealthMonitor.FromJObject方法执行实际的反序列化

最新更新