Сериализация Json.net пользовательской коллекции, реализующая IEnumerable <T>
У меня есть класс коллекции, который реализует IEnumerable, и у меня возникает проблема десериализации сериализованной версии. Я использую Json.net v 4.0.2.13623
Вот более простая версия моего класса коллекции, которая иллюстрирует мою проблему
public class MyType
{
public int Number { get; private set; }
public MyType(int number)
{
this.Number = number;
}
}
public class MyTypes : IEnumerable<MyType>
{
private readonly Dictionary<int, MyType> c_index;
public MyTypes(IEnumerable<MyType> seed)
{
this.c_index = seed.ToDictionary(item => item.Number);
}
public IEnumerator<MyType> GetEnumerator()
{
return this.c_index.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public int CustomMethod()
{
return 1; // Just for illustration
}
}
Когда я сериализую его, я получаю следующий json
[
{
"Number": 1
},
{
"Number": 2
}
]
Но тогда, когда я пытаюсь десериализовать, я получаю следующее исключение
System.Exception: невозможно создать и заполнить тип списка MyTypes
Также попробовали использовать подсказки сериализации, но не имели успеха
Это тестовая функция, которую я использовал
public void RoundTrip()
{
var _myTypes1 = new MyTypes(new[] { new MyType(1), new MyType(2) });
var _jsonContent = JsonConvert.SerializeObject(_myTypes1, Formatting.Indented);
var _myTypes2 = JsonConvert.DeserializeObject<MyTypes>(_jsonContent);
}
public void RoundTripWithSettings()
{
var _myTypes1 = new MyTypes(new[] { new MyType(1), new MyType(2) });
var _serializationSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Arrays };
var _jsonContent = JsonConvert.SerializeObject(_myTypes1, Formatting.Indented, _serializationSettings);
var _myTypes2 = JsonConvert.DeserializeObject<MyTypes>(_jsonContent, _serializationSettings);
}
Кто-нибудь смог сериализовать свои собственные объекты коллекции?
Заранее спасибо
Пат
Ответы
Ответ 1
Я считаю, что JSON.NET зависит от наличия безпараметрического конструктора для типов, которые он десериализует. С точки зрения десериализации она не имеет понятия, что предоставить конструктору.
Что касается вашей коллекции, снова как она должна знать, как заполнить реализацию IEnumerable<T>
, которая определяет только, как перечислять коллекцию, а не как ее заполнять. Вы должны вместо этого десериализоваться непосредственно на некоторый стандартный IEnumerable<MyType>
(или непосредственно на IEnumerable<MyType>
, который, как я полагаю, поддерживает JSON.NET), а затем передать его вашему конструктору.
Я считаю, что в этом случае должно работать следующее:
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<MyTypes[]>(_jsonContent));
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<List<MyTypes>>(_jsonContent));
var _myTypes2 = new MyTypes(JsonConvert.DeserializeObject<IEnumerable<MyTypes>>(_jsonContent));
В качестве альтернативы, хотя больше работы, если вам нужно десериализовать напрямую, вы можете реализовать что-то вроде IList в своей коллекции, что должно позволить JSON.NET использовать методы IList для заполнения вашей коллекции.
Ответ 2
Как и в Json.NET 6.0 Release 3 и более поздних версиях (я тестировал 8.0.3), это работает автоматически, пока пользовательский класс, реализующий IEnumerable<MyType>
, имеет конструктор, который принимает входной аргумент IEnumerable<MyType>
. Из примечания к выпуску:
Для всех будущих создателей неизменяемых коллекций .NET: если ваша коллекция T имеет конструктор, который принимает IEnumerable, то Json.NET будет автоматически работать при десериализации в вашу коллекцию, иначе вам все не повезло.
Поскольку класс MyTypes
в вопросе имеет только такой конструктор, теперь это работает. Демонстрационная скрипка: https://dotnetfiddle.net/LRJHbd.
При отсутствии такого конструктора нужно добавить конструктор без параметров и реализовать ICollection<MyType>
(вместо простого IEnumerable<MyType>
) с помощью рабочего метода Add(MyType item)
. Затем Json.NET может создавать и заполнять коллекцию. Или десериализовать промежуточную коллекцию, как в исходном ответе .