#dart #serialization #deserialization
#dart #сериализация #десериализация
Вопрос:
Пожалуйста, рассмотрите следующий сегмент кода, объявление одного базового класса и двух расширителей.
abstract class Animal {
final bool flag;
Animal(this.flag);
}
class Cat extends Animal {
final String name;
Cat(this.name, bool flag) : super(flag);
Cat.fromJson(Map<String, dynamic> json)
: name = json['name'],
super(json['flag']);
}
class Fish extends Animal {
final int memory;
Fish(this.memory, bool flag) : super(flag);
Fish.fromJson(Map<String, dynamic> json)
: memory = json['memory'],
super(json['flag']);
}
Какова наилучшая практика сериализации и десериализации следующего списка?
List<Animal> animals = [Cat('Nancy', true), Fish(10, false)];
Итак, как сериализовать информацию о типе для каждого класса, чтобы создать соответствующий экземпляр после десериализации?
Код сериализации опущен для простоты, однако он вернет карту полей-членов. Приведенный выше код является лишь примером — в структуре или данных нет смысла.
РЕДАКТИРОВАТЬ: я бы предпочел не использовать какую-либо библиотеку или генератор кода, а использовать внутренние возможности языка.
Любое предложение приветствуется, спасибо.
Ответ №1:
Мне пришлось это выяснить, поэтому я предоставляю свое наивное решение проблемы. Однако, если кто-нибудь предложит лучший подход, я отмечу это как ответ.
Мое наивное решение состоит в том, чтобы украсить каждый результат JSON полем «тип», которое содержит имя подкласса. Тогда я мог бы создать фабрику для базового типа, которая создает соответствующий экземпляр в зависимости от этого поля «тип». Полный код:
abstract class Animal {
final bool flag;
Animal(this.flag);
factory Animal.fromJson(Map<String, dynamic> json) {
switch (json['type']) {
case 'cat':
return Cat.fromJson(json);
case 'fish':
return Fish.fromJson(json);
default:
throw 'Invalid animal type';
}
}
}
class Cat extends Animal {
final String name;
Cat(this.name, bool flag) : super(flag);
Cat.fromJson(Map<String, dynamic> json)
: name = json['name'],
super(json['flag'].toString() == 'true');
Map<String, dynamic> toJson() {
return {'type': 'cat', 'name': name, 'flag': flag.toString()};
}
}
class Fish extends Animal {
final int memory;
Fish(this.memory, bool flag) : super(flag);
Fish.fromJson(Map<String, dynamic> json)
: memory = json['memory'],
super(json['flag'].toString() == 'true');
Map<String, dynamic> toJson() {
return {'type': 'fish', 'memory': memory, 'flag': flag.toString()};
}
Очевидно, что во время десериализации элементы списка должны быть сопоставлены с использованием заводского метода следующим образом:
var data = jsonDecode("[{'type':'cat','name':'Nancy','flag':'true'},{'type':'fish','memory':10,'flag':'false'}]");
List<Animal> list = data.map((e) => Animal.fromJson(e)).cast<Animal>().toList();