如何使用Dart / Flutter到Firestore管理将枚举属性序列化/反序列化?

时间:2018-10-28 20:32:21

标签: enums dart flutter

我需要将Flutter应用程序中的Dart对象存储在Firestore中

该对象包括一个枚举属性。

对该枚举属性进行序列化/反序列化的最佳解决方案是什么?

  • 作为字符串

  • 作为一个整数

我找不到任何简单的解决方案。

6 个答案:

答案 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)

如果有人使用“Dart 数据类生成器”。您需要使用 // 枚举注释进行注释。

enter image description here

enter image description here

答案 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;
}