Подтвердить что ты не робот

Отменить сортировку списка <AbstractClass> с помощью newtonsoft.json

Я пытаюсь сериализовать и десериализовать список классов abstract (mustinherit для vb), obviusly внутри него есть только экземпляры производных классов.

Я украсил параметр списка JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto), получив вывод, который выглядит так:

Но когда я десериализую, он продолжает говорить, что он не может десериализовать абстрактный класс.

http://james.newtonking.com/json/help/index.html?topic=html/SerializeTypeNameHandling.htm

public class ConcreteClass
{
    private ObservableCollection<AbstractClass> _Nodes = new ObservableCollection<AbstractClass>();
    //<Newtonsoft.Json.JsonProperty(itemtypenamehandling:=Newtonsoft.Json.TypeNameHandling.Auto)>
    public ObservableCollection<AbstractClass> Nodes {
        get { return this._Nodes; }
    }
    public string Name { get; set; }
    public int Id { get; set; }
}

public abstract class AbstractClass
{
    private ObservableCollection<AbstractClass> _Nodes = new ObservableCollection<AbstractClass>();
    [Newtonsoft.Json.JsonProperty(itemtypenamehandling = Newtonsoft.Json.TypeNameHandling.Auto)]
    public ObservableCollection<AbstractClass> Nodes {
        get { return this._Nodes; }
    }
}

удаление прокомментированной строки, в которой оно работает!

4b9b3361

Ответ 1

Это была моя ошибка. У меня был конкретный класс, содержащий Список, но я поместил декоратора только в список AbstractClass, забыв о главном.

Ответ 2

Убедитесь, что вы указываете TypeNameHandling при десериализации, как в документах:

// for security TypeNameHandling is required when deserializing
Stockholder newStockholder = JsonConvert.DeserializeObject<Stockholder>(jsonTypeNameAuto, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto
});

Стоит отметить, что документация десериализует класс Concrete, который содержит коллекцию абстрактных классов.

Как эксперимент попробуйте создать класс throw-away (конкретный), который имеет одно свойство с вашим списком абстрактных объектов и посмотреть, можете ли вы сериализовать и десериализировать это.

UPDATE:

Я только что протестировал следующий код в LINQPad:

void Main()
{
    var test = new List<Business>();
    test.Add(new Hotel { Name = "Hilton", Stars = 5 });
    test.Add(new Pool { Name = "Big Splash", Capacity = 500 });

    test.Dump();

    string json = JsonConvert.SerializeObject(test, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All
    });

    json.Dump();

    var businesses = JsonConvert.DeserializeObject<List<Business>>(json, new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All
    });

    businesses.Dump();
}

// Define other methods and classes here
public abstract class Business
{
    public string Name { get;set; }
}
public class Hotel : Business
{
    public int Stars { get;set; }
}
public class Pool : Business
{
    public int Capacity { get;set;}
}

Это сработало отлично. Абстрактная коллекция сериализована для:

{
  "$type": "System.Collections.Generic.List`1[[UserQuery+Business, query_jvrdcu]], mscorlib",
  "$values": [
    {
      "$type": "UserQuery+Hotel, query_jvrdcu",
      "Stars": 5,
      "Name": "Hilton"
    },
    {
      "$type": "UserQuery+Pool, query_jvrdcu",
      "Capacity": 500,
      "Name": "Big Splash"
    }
  ]
}

Оригинальная и десериализованная коллекции совпадают.