При синтаксическом анализе значения обнаружен неожиданный символ: [. исключение при десериализации в поле List‹string›

У меня есть объект:

class Node
{
  public Node(string text)
  {
    Text = new List<string> { text };
  }

  public List<string> Text { get; set; }
}

Когда я пытаюсь передать экземпляр этого объекта в JSON, используя Json.NET, вот так:

var root = new Node("");

var json = JsonConvert.SerializeObject(root);
root = JsonConvert.DeserializeObject<Node>(json);

Я получаю следующую ошибку:

Unhandled Exception: Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: [. Path 'Text', line 2, position 11.
   at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)
   at Newtonsoft.Json.JsonTextReader.ReadAsString()
   at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)

По какой-то причине он просто не может обработать это поле List<string> Text, и я не могу понять это.

Я буквально пытаюсь десериализовать строку, которую она ПРОСТО сериализует. Я мог бы попробовать написать собственный конвертер, но не похоже, что здесь это необходимо.

Возможно, есть атрибут, который я могу использовать, чтобы помочь ему в этом?

Редактировать:

Создал новый проект (консольное приложение .NET Framework) всего с одним файлом Program.cs со следующим кодом:

using Newtonsoft.Json; // Version: 12.0.3
using System.Collections.Generic;

namespace ConsoleApp1
{
  class Node
  {
    public Node(string text)
    {
      Text = new List<string> { text };
    }

    public List<string> Text { get; set; }
  }

  class Program
  {
    static void Main()
    {
      var root = new Node("");

      var json = JsonConvert.SerializeObject(root);
      root = JsonConvert.DeserializeObject<Node>(json);
    }
  }
}

Я все еще получаю ту же ошибку.


person alexania    schedule 30.07.2020    source источник


Ответы (2)


Ваша проблема в том, что ваш класс Node не имеет конструктора без параметров. Вместо этого он имеет один параметризованный конструктор. В таком случае Json.NET вызовет параметризованный конструктор, сопоставляя аргументы конструктора со свойствами JSON по имени, не зависящему от регистра. К сожалению, аргумент text для конструктора не соответствует типу свойства Text. В частности, аргумент представляет собой один string, а свойство представляет собой массив строк:

class Node
{
    public Node(string text /* A single string named text */)
    {
        Text = new List<string> { text };
    }

    public List<string> Text { get; set; } // A collection of strings named Text
}

Поскольку массив строк в JSON не может быть десериализован в одну строку, необходимую для построения вашего класса, вы получаете исключение, которое видите. Демонстрационная скрипта №1 здесь.

Чтобы решить эту проблему, ваши варианты включают в себя:

  1. Добавление конструктора без параметров. Json.NET вызовет его по умолчанию:

    class Node
    {
        public Node() => Text = new List<string>();
    
        public Node(string text /* A single string named text */)
        {
            Text = new List<string> { text };
        }
    
        public List<string> Text { get; set; } // A collection of strings named Text
    }
    

    Он может быть закрытым или защищенным, если вы пометите его [JsonConstructor].

    Демонстрационная скрипта №2 здесь.

  2. Изменение конструктора для приема набора строк. params string [] text казалось бы, проще всего:

    class Node
    {
        public Node(params string [] text)
        {
            Text = text.ToList();
        }
    
        public List<string> Text { get; set; } // A collection of strings named Text
    }
    

    Демонстрационная скрипта №3 здесь.

  3. Переименование аргумента text в конструкторе во что-то другое, скажем, singletext, далеко не идеально, потому что Json.NET передаст null для отсутствующего значения конструктора, которое изначально будет добавлено в коллекцию Text и останется там, пока коллекция не будет впоследствии заменена. во время десериализации.

    Демонстрационная скрипта №4 здесь.

Связанное чтение:

person dbc    schedule 30.07.2020

Итак, я решил проблему, переименовав поле с Text на DialogueText, переименовав его в Texts, это тоже решает ее.

Поскольку я уже безуспешно пытался установить имя через JsonProperty, мое текущее предположение состоит в том, что, возможно, Text является зарезервированным именем поля, которое жестко запрограммировано для ожидания string.

person alexania    schedule 30.07.2020