You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否编写支持多种枚举类型的通用序列化反序列化扩展?

解决Dart枚举序列化/反序列化重复扩展的问题

你的痛点我太懂了——每个枚举都写一遍几乎一模一样的扩展,不仅重复劳动,还容易出错。好在Dart有几种方式可以帮你摆脱这种重复代码:

方法1:写一个泛型通用扩展(原生支持,无需第三方包)

Dart的枚举都继承自Enum类,我们可以基于这个写一个泛型扩展,让所有枚举都能复用序列化/反序列化逻辑:

// 自定义错误类(和你原来的保持一致)
class SerializerError extends Error {
  final String message;
  SerializerError(this.message);
  
  @override
  String toString() => message;
}

// 通用枚举序列化扩展
extension EnumSerialization<T extends Enum> on T {
  // 序列化:直接用枚举自带的name属性(和你原来的split逻辑效果完全一致,但更高效)
  String getString() => name;

  // 反序列化:需要传入目标枚举的values列表,指定泛型类型
  static T fromString(List<T> enumValues, String str) => enumValues.firstWhere(
        (v) => v.name == str,
        orElse: () => throw SerializerError('Invalid string "$str" for enum ${T.runtimeType}'),
      );
}

使用方式:

对于任意枚举,比如MyEnum和OtherEnum:

enum MyEnum { apple, banana }
enum OtherEnum { small, large }

// 序列化
MyEnum.apple.getString(); // 返回 "apple"
OtherEnum.large.getString(); // 返回 "large"

// 反序列化
final myEnumValue = EnumSerialization.fromString(MyEnum.values, "apple"); // 得到 MyEnum.apple
final otherEnumValue = EnumSerialization.fromString(OtherEnum.values, "large"); // 得到 OtherEnum.large

如果觉得反序列化时写EnumSerialization.fromString有点长,也可以给每个枚举加一个极简的扩展,只做转发:

extension MyEnumHelpers on MyEnum {
  static MyEnum fromString(String str) => EnumSerialization.fromString(MyEnum.values, str);
}

// 现在可以直接这样用:
MyEnum.fromString("banana");

这样每个枚举的扩展只需要一行代码,彻底避免重复逻辑。

方法2:用代码生成自动生成(适合大量枚举的场景)

如果你的项目里枚举非常多,甚至想自动生成JSON序列化逻辑,可以用json_serializable包(Dart生态常用的代码生成工具):

  1. 先在pubspec.yaml里添加依赖:
dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  build_runner: ^2.4.4
  json_serializable: ^6.7.1
  1. 给枚举加注解:
import 'package:json_annotation/json_annotation.dart';

part 'my_enum.g.dart';

@JsonEnum(fieldRename: FieldRename.snake_case) // 可选,比如把驼峰转蛇形
enum MyEnum { apple, banana }

// 执行代码生成命令:flutter pub run build_runner build
  1. 生成后会自动得到fromJson和toJson方法:
// 序列化
MyEnum.apple.toJson(); // 返回 "apple"

// 反序列化
MyEnum.fromJson("banana"); // 得到 MyEnum.banana

这种方式完全不用手动写任何序列化逻辑,代码生成器会帮你搞定一切,还能支持自定义命名规则(比如驼峰转蛇形、大写转小写等)。

补充说明:为什么不用你原来的toString().split('.').last?

Dart的枚举自带name属性,它的值就是枚举值的标识符(比如MyEnum.apple.name就是"apple"),和你原来的toString().split('.').last效果完全一样,但name是直接返回字符串,比拆分toString的结果更高效,也更可靠。

内容的提问来源于stack exchange,提问作者ivanesi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 13:37:30