我需要将Flutter应用程序中的Dart对象存储在Firestore中
该对象包括一个枚举属性。
对该枚举属性进行序列化/反序列化的最佳解决方案是什么?
作为字符串
作为一个整数
我找不到任何简单的解决方案。
答案 0 :(得分:10)
Flutter能够生成JSON序列化代码。您可以找到here的教程。它引用了软件包json_annotation。它还包含对枚举序列化的支持。因此,您所需要的就是使用此工具并用import 'package:json_annotation/json_annotation.dart';
enum Vehicle {
@JsonValue("bike") BIKE,
@JsonValue("motor-bike") MOTOR_BIKE,
@JsonValue("car") CAR,
@JsonValue("truck") TRUCK,
}
注释您的枚举值。
来自code docs:
用于指定枚举值序列化方式的注释。
基本上就是全部。现在让我用一个小例子来说明代码。想象一下一个载具的枚举:
vehilce_owner.dart
然后,您可以在一个模型中使用此枚举,例如import 'package:json_annotation/json_annotation.dart';
part 'vehicle_owner.g.dart';
@JsonSerializable()
class VehicleOwner{
final String name;
final Vehicle vehicle;
VehicleOwner(this.name, this.vehicle);
factory VehicleOwner.fromJson(Map<String, dynamic> json) =>
_$VehicleOwnerFromJson(json);
Map<String, dynamic> toJson() => _$VehicleOwnerToJson(this);
}
,如下所示:
flutter pub run build_runner build
这是您需要根据json generation howto提供的内容。现在,您需要运行构建器或watcher,以便让flutter生成代码:
_$VehicleEnumMap
然后,生成的代码将如下所示。看看根据您的@JsonValue
注释生成的// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'vehicle_owner.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
// more generated code omitted here ....
const _$VehicleEnumMap = {
Vehicle.BIKE: 'bike',
Vehicle.MOTOR_BIKE: 'motor-bike',
Vehicle.CAR: 'car',
Vehicle.TRUCK: 'truck',
};
:
{{1}}
答案 1 :(得分:3)
我这样做的方法是只保存枚举的索引。
假设您有一个枚举:
enum Location {
EARTH,
MOON,
MARS,
}
和一个类,它使用以下方法保存枚举:
/// Returns a JSON like Map of this User object
Map<String, dynamic> toJSON() {
return {
"name": this.name,
"location": this.location.index,
};
}
/// Returns [Player] build from a map with informationen
factory Player.fromJson(Map<String, dynamic> parsedJson) {
return new Player(
name: parsedJson['name'],
location: Location.values.elementAt(
parsedJson['location'],
),
);
}
答案 2 :(得分:1)
如果有点不完整,Gunter的答案是正确的。
JSON serializable确实处理将Enum与字符串进行转换,这是生成的示例代码:
const _$HoursEnumMap = <Hours, dynamic>{
Hours.FullTime: 'FullTime',
Hours.PartTime: 'PartTime',
Hours.Casual: 'Casual',
Hours.Contract: 'Contract',
Hours.Other: 'Other'
};
作为回报,它使用这个相当钝的函数将其转换回去:
T _$enumDecode<T>(Map<T, dynamic> enumValues, dynamic source) {
if (source == null) {
throw ArgumentError('A value must be provided. Supported values: '
'${enumValues.values.join(', ')}');
}
return enumValues.entries
.singleWhere((e) => e.value == source,
orElse: () => throw ArgumentError(
'`$source` is not one of the supported values: '
'${enumValues.values.join(', ')}'))
.key;
}
我对此感到非常厌倦,因此决定制作一个小包装以消除复杂性,这对我来说非常方便:
https://pub.dev/packages/enum_to_string
至少在复制/粘贴解决方案上测试了其单元。欢迎任何添加或请求请求。
答案 3 :(得分:0)
最好的方法是使用枚举整数值,因为它是从/向int / enum类型转换的最容易的方法。
您需要注意,只有在修改枚举时最后才添加新的枚举值,否则持久化的值将变得无效。
https://pub.dartlang.org/packages/built_value为类提供代码生成,并具有自己的枚举,并为您执行JSON(反)序列化。
https://pub.dartlang.org/packages/json_serializable似乎直接支持Dart枚举,但我自己并没有使用它。
答案 4 :(得分:0)
答案 5 :(得分:0)
类似于jksevend的方法(保存枚举索引),我是这样解决的,保存了一个可读的字符串。 好处:您可以在现有条目之间插入新的 Enum 条目,而不会中断加载/保存!
class Player
{
String name;
Gender gender;
// functions for jsonEncode and jsonDecode!
Player.fromJson(Map<String, dynamic> json)
: name = json['name'],
gender = getGenderEnum(json['gender']);
Map<String, dynamic> toJson() => {
'name': name,
'gender': getGenderText(gender);
};
}
enum Gender
{
MALE,
FEMALE,
DIVERSE,
}
String getGenderText(Gender gen)
{
switch(gen)
case Gender.MALE:
return "male";
case Gender.FEMALE:
return "female";
case Gender.DIVERSE:
return "diverse";
}
Gender getGenderEnum(String gen) {
for (Gender candidate in Gender.values) {
if (gen == getGenderText(candidate))
return candidate;
}
return Gender.MALE;
}