反序列化动态json类型

时间:2014-12-24 14:59:46

标签: json dynamic json.net

我想反序列化json,它返回不同参数的不同数据。 我得到的主要是:

 {"posts": [{ "id" : 1, "name":"post1" },{ "id" : 1, "name":"post1" }]}

但有时返回的数据是

{"posts": false}

我想将其反序列化为以下类

public class GetReaderResponse
{
   public IEnumerable<ReaderPost> posts {get; set;}
}

public class ReaderPost
{
   public int id {get; set;}
   public string name{get; set;}
}

我正在使用C#,json.net但是无法正确执行此操作。

Newtonsoft.Json.JsonConvert.DeserializeObject<GetReaderResponse>(dataString);

4 个答案:

答案 0 :(得分:2)

您可以构建自定义转换器,但处理此问题的一种简单方法是编写一个错误处理程序,以检测posts属性的错误:

var settings = new JsonSerializerSettings();

settings.Error += (sender, args) =>
{
    if (string.Equals("posts", args.ErrorContext.Path, StringComparison.OrdinalIgnoreCase))
    {
        var currentObject = args.CurrentObject as GetReaderResponse;

        currentObject.posts = Enumerable.Empty<ReaderPost>();

        args.ErrorContext.Handled = true;
    }
};

GetReaderResponse resp = 
    JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);

这会将posts设置为Enumerable.Empty<ReaderPost>。这仍然有点不令人满意,因为如果发生任何错误,将设置该属性。您可以构建一个完整的自定义转换器,以此作为更完整的解决方案。

这是一个能够解决这个问题的转换器:

public class PostsConverter : JsonConverter
{
    public override object ReadJson(
        JsonReader reader,
        Type objectType,
        object existingValue,
        JsonSerializer serializer)
    {
        JToken val = JValue.ReadFrom(reader);
        object result = null;

        if (val.Type == JTokenType.Array)
        {
            result = val.ToObject<IEnumerable<ReaderPost>>();
        }
        else if (val.Type == JTokenType.Boolean)
        {

            result = Enumerable.Empty<ReaderPost>();
        }

        return result;
    }

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

    public override bool CanConvert (Type type)
    {
        return typeof(IEnumerable<ReaderPost>).IsAssignableFrom(type);
    }

    public override bool CanRead
    {
        get { return true; }
    }
}

用法:

var settings = new JsonSerializerSettings();

settings.Converters = new [] { new PostsConverter() };

GetReaderResponse resp = 
    JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);

示例: https://dotnetfiddle.net/i9CXwp

答案 1 :(得分:1)

通过使用LINQ to JSON内置的JSON.NET,您可以尝试这样的事情:

JObject jObject = JObject.Parse(json);
GetReaderResponse response = new GetReaderResponse();
if (jObject["posts"] is JArray)
    response = jObject.ToObject<GetReaderResponse>();

// Do something with the response object.

其中json变量是您需要反序列化的json字符串。

答案 2 :(得分:0)

试试这个:

public class GetReaderResponse
{
    public bool posts { get; set; }
    public ReaderPost[] post { get; set; }
}

答案 3 :(得分:0)

在阅读@Ilija的评论后,我想我可能已经找到了答案。我不想使用字符串文字,因此我将类GetReaderResponse修改为如下所示:

public class GetReaderResponse
{
    public dynamic posts {get; set;}
    public IEnumerable<ReaderPost> Posts
    {
        get
        {
             if (posts is bool )
               return new ReaderPost[0];

           return posts.ToObject<IEnumerable<ReaderPost>>();            
        }
    }
}

这听起来不错还是看起来很麻烦?