Десериализация Json доступа к результату - PullRequest
5 голосов
/ 31 марта 2020

У меня есть Json:

{
   "UpdatePack":"updatePacks\/1585654836.pack",
   "Updates":[
      {
         "Name":"MsgBoxEx",
         "version":"1.5.14.88",
         "ChangeLog":"BugFix: Form didn't resize correct.",
         "Hash":"5FB23ED83693A6D3147A0485CD13288315F77D3D37AAC0697E70B8F8C9AA0BB8"

},
      {
         "Name":"Utilities",
         "version":"2.5.1.58",
         "ChangeLog":"StringManagement updated.",
         "Hash":"05E6B3F521225C604662916F50A701E9783E13776DE4FCA27BE4B69705491AC5"

}

]
}

Я создал 2 класса для его десериализации.

class UpdatesList
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string ChangeLog { get; set; }
    public string Hash { get; set; }
}
class JsonObjectHolder
{
    public string UpdatePack { get; set; }
    //public Dictionary<int, MyData> { get; set; }
    public Dictionary<int, UpdatesList> Updates { get; set; }
}

Но когда я пытаюсь получить доступ к словарю, я продолжаю получать Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at " Console.WriteLine(jsonTest.Dict.Count);"

Я неправильно десериализирую его, или мне нужно сделать что-то еще, чтобы получить доступ к результату словаря?

Я новичок в обоих C# и Json.

Я надеюсь, что кто-то может указать мне правильное направление, как справиться с этим.

Я использую последнее обновление Visual Studio 2019 и. net 4.8 , С уважением / LR

Ответы [ 4 ]

6 голосов
/ 31 марта 2020

Ваш код не работает, потому что 0 и 1 являются маркерами только свойств, а не элементов массива (у вас нет квадратных скобок [] вокруг них). Вы можете проанализировать эти значения для желаемой структуры вручную, используя JObject

var json = JObject.Parse(your_json_string);
var dict = new Dictionary<int, UpdatesList>();
foreach (var item in json.Properties())
{
    if (item.Value.Type == JTokenType.Object)
    {
        var index = int.Parse(item.Name);
        var updateList = item.Value.ToObject<UpdatesList>();
        dict.Add(index, updateList);
    }
}

var holder = new JsonObjectHolder
{
    UpdatePack = json["Updates"]?.Value<string>(),
    Dict = dict
};

Обновление: В соответствии с изменениями OP, внесенными в JSON, оно может быть десериализовано даже Проще говоря

var list = json["Updates"]?.ToObject<List<UpdatesList>>();

var holder = new JsonObjectHolder
{
    UpdatePack = json["UpdatePack"]?.Value<string>(),
    Dict = list.Select((updatesList, index) => new { updatesList, index })
                    .ToDictionary(x => x.index, x => x.updatesList)
};

Суть в том, что Updates - это массив элементов, а не набор значений ключей. Его можно преобразовать в Dictionary<int, UpdatesList>, используя ToDictionary метод из System.Linq (или просто использовать List<UpdatesList> как есть)

2 голосов
/ 31 марта 2020

Я не понимаю, зачем вам нужен Dictionary<int, UpdatesList> Updates, когда вы можете просто использовать List<Update> Updates, поскольку ваши обновления находятся в массиве JSON.

Я бы смоделировал ваши классы следующим образом:

public class Update
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string ChangeLog { get; set; }
    public string Hash { get; set; }
}

public class RootObject
{
    public string UpdatePack { get; set; }
    public List<Update> Updates { get; set; }
}

Затем вы можете десериализовать с помощью:

 JsonConvert.DeserializeObject<RootObject>(json);

Попробуйте это на dotnetfiddle. net

Примечание: Чтобы преобразовать JSON в C# классы, вы можете go в Правка -> Специальная вставка -> Вставить JSON как классы внутри Visual Studio. Убедитесь, что вы скопировали JSON в буфер обмена, прежде чем использовать его. Вы получите классы, похожие на выше.

2 голосов
/ 31 марта 2020

Исключение, которое вы получаете по существу, означает, что к значению обращаются до инициализации объекта.

Лучший, более простой и понятный способ сделать это - использовать NewtonSoft. (вы можете легко получить его как пакет Nuget)

пример:

public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}

и затем использование:

string json = @"{
  'Email': 'james@example.com',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);

Источник: https://www.newtonsoft.com/json/help/html/DeserializeObject.htm

0 голосов
/ 31 марта 2020

ваши данные и класс не совместимы. если вы измените строку таким образом, она будет работать.

замените «Updates» на «UpdatePack» и добавьте «Dict» вокруг элементов словаря.

{
   "UpdatePack":"updates\/4D1D7964D5B88E5867324F575B77D2FA.zip",
   "Dict":{
      "0":{
         "Name":"MsgBoxEx",
         "Version":"1.0.123.58",
         "ChangeLog":"Bugfix:Form didn't resize correct",
         "hash":"AA94556C0D2C8C73DD217974D252AF3311A5BF52819B06D179D17672F21049A6"
      },
      "1":{
         "Name":"Utilities",
         "Version":"1.5.321.87",
         "ChangeLog":"StringManagement updated",
         "hash":"2F561B02A49376E3679ACD5975E3790ABDFF09ECBADFA1E1858C7BA26E3FFCEF"
      }
   }
}
...