Подтвердить что ты не робот

Deserializing JSON - как игнорировать корневой элемент?

Я использую службу WCF, которая возвращает результаты JSON, завернутые внутри корневого элемента 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);

или что-то в этом роде...

4b9b3361

Ответ 1

Если вы знаете, что искать, например, в этом случае "d", который является корневым node, вы можете сделать следующее.

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[]>();
                }
            }
        }

Ответ 2

По Newtonsoft, я полагаю, вы используете JSon.net, вот мое решение, я использовал Linq для 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, потому что вам нужно найти первый node после d, который является первым node полученного вами json.

Вам просто нужно создать функцию, которая воспроизводит Main, не забудьте проверить, не являются ли объекты ненулевыми, чтобы избежать NullReferenceException.

Ответ 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);