Десериализация защищенного сконструированного объекта из json

#c# #.net #constructor #json.net #deserialization

#c# #.net #конструктор #json.net #десериализация

Вопрос:

Я использую newton’s json.net сериализатор. При десериализации json в ‘TheFox’; он попадает в защищенный ctor и получает значения свойств по умолчанию. Но не значения свойств в строке json. Могу ли я решить эту проблему без использования dto или любого другого фреймворка mapper?

 class TheFox
    {

    string _Id;
    string _Name;

    protected TheFox()
    {
        _Id = "Default Id";
        _Name = "Default Name";
    }

    public TheFox(string id, string name) : this()
    {
        _Name = name;
        _Id = id;
    }

    public string Id
    {
        get { return _Id; }
    }

    public string Name
    {
        get { return _Name; }
    }
}
  

Это тест:

         var fox = new TheFox("FoxId", "FoxTail");
        var json = JsonConvert.SerializeObject(fox);
        Console.WriteLine(json);

        var settings = new JsonSerializerSettings ()
        {
            ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
        };

        var returned = JsonConvert.DeserializeObject<TheFox> (json, settings);

        Assert.IsTrue (returned.Id != "Default Id");
        Assert.IsTrue (returned.Name != "Default Name");
  

Комментарии:

1. Странно, что так много десериализаторов не поддерживают параметризованные конструкторы.

Ответ №1:

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

 private void SetPropertyValue(JsonProperty property, JsonReader reader, object target)
    {
      // bla.. bla.. bla..
      if (!property.Writable amp;amp; !useExistingValue)
      {
        reader.Skip();
        return;
      }
  

Этот метод плохой, для его заполнения требуется созданный объект, но он работает.

 var a = new TheFox("x", "y");
var json = JsonConvert.SerializeObject(a);
Console.WriteLine(json);

var returned = JsonConvert.DeserializeAnonymousType(json, new TheFox("q", "a")); 

Assert.That(a.Id, Is.EqualTo(returned.Id));
Assert.That(a.Name, Is.EqualTo(returned.Name));
  

Комментарии:

1. Вы категорически против использования защищенных или даже частных установщиков для этих свойств? Это помогло бы вам, если бы использовалось с аннотацией [JsonProperty].

Ответ №2:

     class TheFox
    {
      string _Id;
      string _Name;

      protected TheFox() : this("Default Id", "Default Name")

      public TheFox(string id, string name)
      {
        _Name = name;
        _Id = id;
      }

      public string Id
      {
        get { return _Id; }
      }

      public string Name
      {
        get { return _Name; }
      }
}
  

Это должно допускать такое же использование, но обеспечивает сопоставимость с newton.

Комментарии:

1. два ваших конструктора вызывают сами себя рекурсивно. Я удалил параметрический ctor и запустил тест. Нет, результат не изменился. по-прежнему используются значения по умолчанию.

2. Извините, это последний раз, когда я пытаюсь писать код на iPad! Исправлены ошибки.

Ответ №3:

Ваш класс не подходит для работы на стороне клиента. Вам нужно использовать атрибут DataContractAttribute для класса и атрибут DataMemberAttribute для элементов, которые вы хотите сериализовать.

Комментарии:

1. я просто десериализирую свой объект с помощью фреймворка. у меня нет никаких дел с wcf.