Использование Json.Net для анализа двух семантически идентичных документов иерархии и сбой

У меня есть два документа JSON, которые представляют одинаковую иерархическую структуру и содержание. Единственное различие, которое я вижу между этими двумя документами, состоит в том, что порядок пар ключ-значение различен. Один документ анализируется, как я ожидаю, а другой нет.

Я использую "Сохранение ссылок", поэтому узел должен ссылаться на своего родителя. (Переменная "ierarchyTwoNode"в тесте - это документ, для которого не установлено свойство Parent). Я включил тест ( можно найти здесь), чтобы продемонстрировать это. Вот упрощенная версия рабочего JSON:

{
  "Root": {
    "$id": "1",
    "Id": "1472459628771017730",
    "Type": "cras",
    "Content": {
      "Name": "lorem"
    },
    "Parent": null,
    "Children": [
      {
        "$id": "2",
        "Id": "1472459628812960771",
        "Type": "morbi",
        "Content": {
          "Name": "ipsum dolor"
        },
        "Parent": {
          "$ref": "1"
        }
      }
    ]
  }
}

И провальный JSON:

{
  "Root": {
    "Parent": null,
    "$id": "1",
    "Children": [
      {
        "Parent": {
          "$ref": "1"
        },
        "$id": "2",
        "Content": {
          "Name": "ipsum dolor"
        },
        "Type": "morbi",
        "Id": "1472459628812960771"
      }
    ],
    "Content": {
      "Name": "lorem"
    },
    "Type": "cras",
    "Id": "1472459628771017730"
  }
}

Может ли кто-нибудь дать мне представление о том, что происходит?

2 ответа

Решение

Может ли кто-нибудь дать мне представление о том, что происходит?

По сути, происходит то, что в одной из строк JSON ваши свойства метаданных размещаются после первого фактического свойства.

все $xxx свойства являются метаданными и должны быть размещены в начале объекта / подобъекта.

Причина этого ограничения заключается в следующем:

если мы посмотрим на внутреннюю часть JSON.Net, при выполнении поиска метаданных мы увидим, что как только мы читаем свойство, которое не является метаданными, мы прекращаем поиск метаданных.

Я могу только предположить, что он предназначен для оптимизации вычислений и памяти, если файл JSON будет очень большим.

Чтобы ваш код работал, просто поместите все свойства, начинающиеся с $ в начале объекта, и он должен работать как шарм.

Как правильно вывел @Fabio Salvalai, Json.Net обычно ожидает любые свойства метаданных (например, $id или же $type) появляться первым в каждом объекте для лучшей эффективности в десериализации. Если метаданные не появляются первыми, Json.Net предполагает, что их там нет. Вот почему вы получаете разные результаты, когда свойства переупорядочены.

К счастью, Json.Net предоставляет MetadataPropertyHandling настройки, чтобы позволить ему справиться с этой ситуацией. Если вы установите MetadataPropertyHandling в ReadAhead это должно решить вашу проблему. Обратите внимание, что это может повлиять на производительность, если ваш JSON большой.

JsonSerializerSettings settings = new JsonSerializerSettings
{
    MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
};

var hierarchyOne = JsonConvert.DeserializeObject<Hierarchy>(HierarchyOne, settings);
var hierarchyTwo = JsonConvert.DeserializeObject<Hierarchy>(HierarchyTwo, settings);
Другие вопросы по тегам