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

fvi*_*cot 18 enums dart flutter

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

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

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

  • 作为字符串

  • 作为一个 Int

我没有找到任何简单的解决方案来做到这一点。

Pau*_*aul 35

最新的枚举实现

简而言之,使用以下枚举序列化的最新实现:

fromJson -> YourEnum.values.byName("property")

toJson -> YourEnum.property。name

toJson/fromJson在你的枚举上

只需将这两个函数添加到您的枚举中即可。请注意,您也可以简单地在类中创建这些函数。

enum Manufacturer {
  mercedes,
  volkswagen,
  toyota,
  ford;

  String toJson() => name;
  static Manufacturer fromJson(String json) => values.byName(json);
}
Run Code Online (Sandbox Code Playgroud)

例子

class Car {
  final String name;
  final Manufacturer manufacturer;

  Car(this.name, this.manufacturer);

  Map<String, dynamic> toJson() {
    return {
      "name": name,
      "manufacturer": manufacturer.toJson(), // Alternative: manufacturer.name
    };
  }

  static Car fromJson(Map<String, dynamic> jsonData) => Car(
        jsonData['name'],
        Manufacturer.fromJson(jsonData['manufacturer']), // Alternative: Manufacturer.values.byName(jsonData['manufacturer'])
      );
}
Run Code Online (Sandbox Code Playgroud)


Ada*_*dam 34

Flutter 能够生成 JSON 序列化代码。您可以在此处找到教程。它引用了包json_annotation。它还包含对枚举序列化的支持。所以你所需要的就是使用这个工具并用@JsonValue.

代码文档

用于指定枚举值如何序列化的注释。

这基本上就是全部。现在让我用代码中的一个小例子来说明。想象一个带有车辆的枚举:

import 'package:json_annotation/json_annotation.dart';

enum Vehicle {
  @JsonValue("bike") BIKE,
  @JsonValue("motor-bike") MOTOR_BIKE,
  @JsonValue("car") CAR,
  @JsonValue("truck") TRUCK,
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的模型之一中使用这个枚举,例如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);
}
Run Code Online (Sandbox Code Playgroud)

这是你需要根据json生成howto提供的。现在你需要运行构建器或观察器让 flutter 生成代码:

flutter pub run build_runner build
Run Code Online (Sandbox Code Playgroud)

然后生成的代码将如下所示。看一下根据_$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',
};
Run Code Online (Sandbox Code Playgroud)


Rya*_*ell 13

如果有点不完整,Gunter 的回答是正确的。

JSON serializable 确实处理了 Enum 与字符串之间的相互转换,以下是生成内容的一些示例代码:

const _$HoursEnumMap = <Hours, dynamic>{
  Hours.FullTime: 'FullTime',
  Hours.PartTime: 'PartTime',
  Hours.Casual: 'Casual',
  Hours.Contract: 'Contract',
  Hours.Other: 'Other'
};
Run Code Online (Sandbox Code Playgroud)

作为回报,它使用这个相当钝的函数将其转换回来:

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;
}
Run Code Online (Sandbox Code Playgroud)

我厌倦了这个我决定做一个小包来消除复杂性,它对我来说非常方便:

https://pub.dev/packages/enum_to_string

至少它的单元通过复制/粘贴解决方案进行了测试。欢迎任何添加或请求请求。


jks*_*end 5

我这样做的方法是只保存枚举的索引。

假设您有一个枚举:

enum Location {
  EARTH,
  MOON,
  MARS,
}
Run Code Online (Sandbox Code Playgroud)

以及一个使用以下方法保存枚举的类:

/// 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'],
      ),
    );
  }
Run Code Online (Sandbox Code Playgroud)

  • 这样做的缺点是可维护性:下一个修改枚举的人(或者甚至是你自己,如果是一年后)可能不知道索引和排序是至关重要的。例如,如果将一个值添加到列表的开头,那么您就彻底完蛋了。 (9认同)

Gün*_*uer 1

最好的方法是使用 enums 整数值,因为它是最容易从 int/enum 类型转换到 int/enum 类型的。

您需要注意的是,仅在修改枚举时才在末尾添加新的枚举值,否则持久化的值将变得无效。

https://pub.dartlang.org/packages/built_value提供类的代码生成,并拥有自己的枚举,并为您进行 JSON(反)序列化。

https://pub.dartlang.org/packages/json_serialized似乎直接支持 Dart 枚举,但我自己没有使用过。

  • “最好的方法是使用枚举整数值”,然后是“您需要注意仅在末尾添加新的枚举值[...],否则持久值将变得无效”与我相矛盾。 (3认同)