0

Есть json.

{
    "1": {
        "m": "StatTrak™ AK-47 | Blue Laminate (Field-Tested)",
        "c": 1,
        "g": 3,
        "z": 2,
        "e": "FT",
        "v": 20,
        "h": 4,
        "u": "kxu",
        "w": 1,
        "j": "StatTrak™ AK-47 | Синий глянец (После полевых испытаний)"
    },
    "2": {
        "m": "StatTrak™ P250 | Valence (Field-Tested)",
        "c": 1,
        "g": 5,
        "z": 1,
        "e": "FT",
        "v": 13,
        "h": 2,
        "u": "kwd",
        "w": 31,
        "j": "StatTrak™ P250 | Валентность (После полевых испытаний)"
    }
}

Преобразовал его в класс

public class Data
{
    public string m { get; set; }
    public int c { get; set; }
    public int g { get; set; }
    public int z { get; set; }
    public string e { get; set; }
    public int v { get; set; }
    public int h { get; set; }
    public string u { get; set; }
    public int w { get; set; }
    public string j { get; set; }
}

public class RootObject
{
    public Data[] data { get; set; }
}

При попытке сериализации выдает ошибку

var res = js.Deserialize<Data[]>(json)

Для типа "WindowsFormsApp21.Data[]" не определен конструктор без параметров."

Yuri
  • 1

1 Answers1

3

Способ первый самый простой

Когда нужны все данные из json.

public class Data
{
    public string m { get; set; }
    /* куча проперти */
}

var  data = JsonConvert.DeserializeObject<Dictionary<string, Data>>(json)

Почему тип Dictionary<string, Data>, т.к. у вас именно JObject идет первым (как я это определил ниже), то все элементы на его верхнем уровне считаются JProperty. У каждого есть имя и значение, где в качестве значения может быть друга вложенная структура данных. В нашем случае словарь по сути это массив этих самых JProperty, где key=имя проперти и value=значение.

Как я опередил что это JObject. Первый уровень не имеет ни одного JProperty и начинается с фигурных скобок. Пример ниже будет уже считаться JArray. Такой формат библиотека newtonsoft считает массивом.

{
    [{
        "m": "StatTrak™ AK-47 | Blue Laminate (Field-Tested)",
        "c": 1
    },
    {
        "m": "StatTrak™ P250 | Valence (Field-Tested)",
        "c": 1
    }]
}

Разбор в словарь также подходит для случаев, когда ваш json имеет похожую структуру, но поля разные. Например как здесь.

[
    {
        "filterType": "PRICE_FILTER",
        "minPrice":"0.01000000",
        "maxPrice":"10000000.00000000",
        "tickSize":"0.01000000"
    },
    {
        "filterType":"LOT_SIZE",
        "minQty":"0.00001000",
        "maxQty":"10000000.00000000",
        "stepSize":"0.00001000"
    },
    {
        "filterType":"MIN_NOTIONAL",
        "minNotional":"10.00000000"
    }
]

В таком случае вам не нужно будет создавать один класс со всеми этими полями.

var  data = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(json)

В случае если все таки решитесь на отдельный класс, то все проперти, которые не будут найдены в json останутся инициализированы по дефолту.

Второй вариант, но мудренее

var data = JObject.Parse(a)
    .SelectTokens("$.*")
    .Select(o => o.ToObject<Data>())
    .ToArray();

Переменная data будет типом Data[], но значения 1,2 будут потеряны. Этот вариант применим, когда исходный json очень большой и имеет сложную структуру, вам не нужны все данные из него, то делать структуру 1 в 1 неразумно. В этом случае можно вытащить с помощью xpath нужные элементы. Xpath это путь до элемета/ов. Работает по такому же принципу, как select запрос в бд. С его помощью можно указать путь и условия по которым вы хотите собрать данные.


  • С помощью этого сайта можно практиковать xpath запросы для json структуру
  • А с помощью этого можно получать структуры, которые будет соответствовать вашему json.
  • Здесь можно почитать о всех фишках библиотеки Newtonsoft
Adrug
  • 1,301
  • Во первых, десериализация в JObject - не лучший вариант... Во вторых, зачем так сложно? Нужно просто использовать правильный тип. В указанном JSON имеется массив словарей, где ключ - это цифра, а значение - объект. Так зачем эти манипуляции (выбирать что то, потом приводить в нужный вид), если просто можно сразу указать Dictionary<int, Class> как основной тип для десериализации... Не понимаю я вас... – EvgeniyZ May 18 '18 at 14:44
  • @EvgeniyZ это один из возможных способов получения результата. Сейчас может он не такой оптимальный, но зато автор будет знать, что JsonConverter не единственный способ. Не лучший вариант когда json не как JObject пришел, а допустим JArray? – Adrug May 18 '18 at 14:54
  • Хотите показать как можно - напишите дополнительно и правильно, но не так, что вы сотню конвертаций делаете для получения результата, где это совершенно не нужно. И как понять " когда json не как JObject пришел, а допустим JArray"? JSON - он и в африке JSON, он есть валидный и не валидный. Для валидного JSON достаточно сделать нормальную структуру классов и работать как положено, а что у вас? "Там что то потеряли, тут что то потеряли", зачем так? Я не собираюсь тут с вами спорить дальше, просто высказался о том, что считаю ваш подход неверным, кстати в SelectTokens достаточно указать *. – EvgeniyZ May 18 '18 at 15:14
  • @EvgeniyZ никто ничего не терял. Мой вариант работает? Разве я писал в ответе, что это единственно правильный вариант? Json может быть очень большой вложенности и делать похожую структуру не всегда разумно. Бесспорно, сейчас проще через словарь. С вами не собирался спорить. Вы спросили, я ответил. Вы высказываетесь просто, но читается это как претензия якобы я схалтурил. – Adrug May 18 '18 at 15:21
  • "но значения 1,2 вы потеряете". Если восприняли это все притензией, то извиняюсь. Я просто считаю, что надо работать с тем, что имеется в данным момент у автора и помочь ему сделать все грамотно, вы же предлагаете как по мне - костыльный и очень грамотный вариант. Что касается вложенности - тут вы не правы, если есть грамотная структура под этот JSON - вы получаете уйму преимуществ, к примеру расширяемость, ведь вам достаточно переделать пару свойств в классе и в нужных местах подправить вызовы этих свойств и все. – EvgeniyZ May 18 '18 at 15:31
  • В общем в течение получаса удалю ответ, чтобы не смущать других читающих. Сообщаю вам чтобы вы не волновались лишний раз. – Adrug May 18 '18 at 15:35
  • Удалять - дело ваше, я бы на вашем месте просто дописал бы нужное в ответ и привел бы примеры того, как можно поступить еще с описанием плюсов и минусов того или иного варианта... – EvgeniyZ May 18 '18 at 15:46
  • @EvgeniyZ превратил комментарии в чат, но попытался объяснить разницу. – Adrug May 18 '18 at 16:42
  • 2
    И плодами этого всего стал вполне хороший ответ, который даже грех не лайкнуть. Был бы такой ответ без всего этого? Я думаю нет... – EvgeniyZ May 18 '18 at 20:22