Мне нужно сериализовать некоторые настраиваемые объекты для хранения информации. Однако я изо всех сил пытаюсь десериализовать эти объекты из сериализованной строки JSON обратно в их исходные формы объектов.

Сериализованная строка выглядит нормально:

[
  {
    "MyStringArray": [
      "stringInput1",
      "stringInput2"
    ],
    "MyCharArray": [
      "a",
      "b",
      "c",
      "."
    ],
    "MyString": "dummy",
    "MyClass3Object": [
      {
        "MyString": "ListInput1"
      },
      {
        "MyString": "ListInput2"
      }
    ]
  }
]

Однако, когда я реконструирую исходный объект MyClass1, в списке есть одна запись, как и должно быть, но она заполняется нулями вместо соответствующих данных. Есть идеи относительно того, что может происходить? Заранее спасибо за мозговой штурм :)

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.IO;
using System.Text.RegularExpressions;

namespace JsonTesting
{
  class Program
  {
    static void Main(string[] args)
    {

      MyClass1 c1 = new MyClass1();
      c1.AddInfo();

      string toJsonString = JsonConvert.SerializeObject(c1, Formatting.Indented,
        new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Include });
      File.WriteAllText(@"C:\temp\dumpJsonText.txt",toJsonString);
      MyClass1 fromJson = JsonConvert.DeserializeObject<MyClass1>(toJsonString);
      Console.ReadLine();

    }
  }


  public class MyClass1 : List<MyClass2> {
    public MyClass1() { }
    public void AddInfo() {
      this.Add(new MyClass2(new string[] { "stringInput1", "stringInput2" },
        new char[] { 'a', 'b', 'c', '.' },
        "dummy",
        new List<MyClass3>() { new MyClass3("ListInput1", new Regex(@"[A-Z]")), new MyClass3("ListInput2", new Regex(@"[0-9]")) }
        ));
    }
  }

  public class MyClass2
  {
    private string[] _myStringArray = null;
    private char[] _myCharArray = null;
    private string _myString = null;
    private List<MyClass3> _myClass3Object = null;

    public MyClass2() { }

    public MyClass2(string[] myStringArray, char[] myCharArray, string myString, List<MyClass3> myClass3Object)
    {
      _myStringArray = myStringArray;
      _myCharArray = myCharArray;
      _myString = myString;
      _myClass3Object = myClass3Object;
    }

    public string[] MyStringArray { get { return _myStringArray; } }
    public char[] MyCharArray { get { return _myCharArray; } }
    public string MyString { get { return _myString; } }
    public List<MyClass3> MyClass3Object { get { return _myClass3Object; } }

  }

  public class MyClass3 {

    private Regex _myRegex; 
    private string _myString = null;
    public MyClass3() { }
    public MyClass3(string myString, Regex myRegex) {

      _myString = myString;
      _myRegex = myRegex;
    }

    public string MyString{ get {return _myString;} }

  }

}
2
Rafael Sanchez 9 Янв 2017 в 18:39
У вас нет общедоступных пустых конструкторов, поэтому он не знает, как создавать вложенные объекты.
 – 
Phill
9 Янв 2017 в 18:41
У меня есть пустой конструктор во всех трех классах. Я просто забыл добавить его сюда.
 – 
Rafael Sanchez
9 Янв 2017 в 18:45
Вы спрашиваете, почему очень конкретный код ведет себя некорректно, тогда вы разместили псевдокод
 – 
Jonesopolis
9 Янв 2017 в 18:46
Я написал код именно так, как в моем проекте, только изменил имена и опустил нерелевантные методы.
 – 
Rafael Sanchez
9 Янв 2017 в 18:48
2
Предоставьте минимальный воспроизводимый пример, воспроизводящий проблему, чтобы можно было получить более точные ответы
 – 
Nkosi
9 Янв 2017 в 18:49

1 ответ

Лучший ответ

Ваши классы MyClass2 и MyClass3 доступны только для чтения. Чтобы Json.NET десериализовал тип, доступный только для чтения, необходимо указать custom JsonConverter, который вручную десериализует и создает экземпляр типа, или предоставляет параметризованный конструктор, имена аргументов которого соответствуют именам свойств по модулю регистра . Вы уже создали необходимые конструкторы и наполовину готовы.

Однако ваши типы также имеют конструкторы без параметров. Итак, какой конструктор вызывает Json.NET? Для неперечислимого типа, сериализованного в объект JSON применяются следующие правила:

  1. Если [JsonConstructor] установлен в конструкторе, используйте это конструктор.

  2. Затем в только полное доверие < / a>, когда применяется MemberSerialization.Fields , или [Serializable] и DefaultContractResolver.IgnoreSerializableAttribute == false, специальный метод FormatterServices.GetUninitializedObject() используется для размещения объекта. Ни один из конструкторов типа не вызывается.

    (Это необычный случай, который возникает нечасто.)

  3. Затем, если есть общедоступный конструктор без параметров, используйте его.

  4. Затем, если существует частный конструктор без параметров и параметр ConstructorHandling.AllowNonPublicDefaultConstructor включен, используется закрытый конструктор без параметров.

  5. Затем, если существует единственный общедоступный параметризованный конструктор, используйте этот конструктор.

  6. При отсутствии всего вышеперечисленного Json.NET не может создавать экземпляры типа. Во время десериализации будет выброшено исключение, если не доступен специальный конвертер.

Таким образом, конструкторы без параметров имеют приоритет перед параметризованными конструкторами. Чтобы принудительно использовать параметризованные конструкторы, пометьте их [JsonConstructor], как указано выше:

public class MyClass3
{
    private Regex _myRegex;
    private string _myString = null;

    public MyClass3() { }

    [JsonConstructor]
    // The argument names must match the property names modulo case for Json.NET to deserialize the properties successfully.
    public MyClass3(string myString, Regex myRegex)
    {
        _myString = myString;
        _myRegex = myRegex;
    }

    public string MyString { get { return _myString; } }

    public Regex MyRegex { get { return _myRegex; } }
}

В качестве альтернативы вы можете исключить конструктор без параметров, поскольку он, по-видимому, не существовал в первой версии вашего вопроса. Затем сделайте то же самое для MyClass2. Теперь ваши типы будут успешно десериализованы.

Обратите внимание, что Json.NET имеет встроенный конвертер для сериализации Regex.

Пример скрипки.

2
dbc 26 Янв 2017 в 14:37
Я добавил [JsonConstructor] в MyClass2 и MyClass3, и он работает :) Спасибо за такой четкий ответ!
 – 
Rafael Sanchez
10 Янв 2017 в 11:49