反序列化JSON - 如何忽略根元素?

23

我正在调用返回JSON结果的WCF服务,这些结果被包装在“d”根元素中。JSON响应如下:

{"d":[
  {
    "__type":"DiskSpaceInfo:#Diagnostics.Common",
    "AvailableSpace":38076567552,
    "Drive":"C:\\",
    "TotalSpace":134789197824
  },
  {
    "__type":"DiskSpaceInfo:#Diagnostics.Common",
    "AvailableSpace":166942183424,
    "Drive":"D:\\",
    "TotalSpace":185149157376
  }
]}

我不想使用动态类型,我有我的类Diagnostics.Common.DiskSpaceInfo,在反序列化时希望使用它。

我正在使用Json.NET(Netwonsoft JSON)。

问题是如何告诉它忽略根元素(即'd'元素),并解析里面的内容。

到目前为止,我找到的最好的解决方案是使用匿名类型:

DiskSpaceInfo[] result = JsonConvert.DeserializeAnonymousType(json, new
    {
        d = new DiskSpaceInfo[0]
    }).d;

这实际上是起作用的,但我不太喜欢它。还有其他方法吗?我想要的是像这样的东西:

DiskSpaceInfo[] result = JsonConvert.Deserialize(json, skipRoot: true);

或类似的东西......


+1 因为我喜欢你的匿名类型解决方案。 - default.kramer
1
相关问题询问如何在不解析到中间 JToken 的情况下完成此操作:JSON.NET 反序列化特定属性 - dbc
3个回答

22

如果您知道要搜索的内容,比如此例中的" d "作为根节点,那么可以执行以下操作。

JObject jo = JObject.Parse(json);
DiskSpaceInfo[] diskSpaceArray = jo.SelectToken("d", false).ToObject<DiskSpaceInfo[]>();

如果你只想忽略你不知道的根类,那么你可以使用 "@Giu Do" 的解决方案,只需要使用 test2.ToObject<DiskSpaceInfo[]>(); 而不是 Console.Write(test2);

        JObject o = JObject.Parse(json);
        if (o != null)
        {
            var test = o.First;
            if (test != null)
            {
                var test2 = test.First;
                if (test2 != null)
                {
                    DiskSpaceInfo[] diskSpaceArray = test2.ToObject<DiskSpaceInfo[]>();
                }
            }
        }

谢谢!很好的解决方案,我试过了,它们都有效。我会保持话题开放,以防有人提供不同的方法,然后我会将您的答案标记为该话题的答案。然而,没有特别的解决方案让我更喜欢它(包括我的原始匿名类型方法)。也许我可以进行一些基准测试,看看这三种方法中是否有性能优势。 - Nikolaos Georgiou

3

继之前的回答,我建议您使用自己的静态实用类。这是可重复使用的,并且可以让您获得所需的语法。

public static class JsonUtil
{
    public static T Deserialize<T>(string json, bool ignoreRoot) where T : class
    {
        return ignoreRoot 
            ? JObject.Parse(json)?.Properties()?.First()?.Value?.ToObject<T>()
            : JObject.Parse(json)?.ToObject<T>();
    }
}

您可以这样调用它:
var resultA = JsonUtil.Deserialize<DiskSpaceInfo[]>(json, ignoreRoot: true);

或者

var resultB = JsonUtil.Deserialize<DiskSpaceInfoRoot>(json, ignoreRoot: false);

1

通过Newtonsoft,我假设您使用JSon.net,这是我的解决方案,我使用了此框架中提供的Linq to JSon:

using System;
using Newtonsoft.Json.Linq;

namespace JSonTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string json = @"{""d"":[
  {
    ""__type"":""DiskSpaceInfo:#Diagnostics.Common"",
    ""AvailableSpace"":38076567552,
    ""Drive"":""C:\\"",
    ""TotalSpace"":134789197824
  },
  {
    ""__type"":""DiskSpaceInfo:#Diagnostics.Common"",
    ""AvailableSpace"":166942183424,
    ""Drive"":""D:\\"",
    ""TotalSpace"":185149157376
  }
]}";
        JObject o = JObject.Parse(json);

        if (o != null)
        {
            var test = o.First;

            if (test != null)
            {
                var test2 = test.First;
                if (test2 != null)
                {
                    Console.Write(test2);
                }
            }
        }

        Console.Read();

    }
}
}

我使用了 First 属性,因为您需要找到在 d 后面的第一个节点,这是您收到的 json 的第一个节点。

您只需要创建一个重现 Main 的函数,不要忘记检查对象是否为空,以避免 NullReferenceException


感谢Giu Do提供Json.NET的命名,我在原问题中进行了编辑。关于你的解决方案,我该如何将test2强制转换为正确的类型DiskSpaceInfo?test2仍然是JToken类型。 - Nikolaos Georgiou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接