Dart中能否定义含重复JsonValue的枚举?多值映射最优方案
Dart多数值映射到同一枚举项的实现方案
直接用多@JsonValue注解行不通
Dart的枚举成员不支持绑定多个@JsonValue注解——不管是语言本身的限制,还是json_serializable这类序列化库的设计逻辑,都不允许同一个枚举项关联多个JSON值。你贴的示例代码实际编译时会报错,就算不报错,重复的@JsonValue也只会生效最后一个,根本达不到多值映射的目的。
最优处理方式
1. 自定义JsonConverter(适配json_serializable场景,推荐)
如果用json_serializable做序列化,最优雅的方式是自定义转换器,手动实现数值和枚举的双向映射:
import 'package:json_annotation/json_annotation.dart'; enum TypeEnum { add, sub } class TypeEnumConverter implements JsonConverter<TypeEnum, int> { const TypeEnumConverter(); @override TypeEnum fromJson(int json) { switch (json) { case 0: case 1: case 3: case 9: case 10: case 11: case 12: return TypeEnum.add; case 2: case 4: case 5: case 6: case 7: case 8: return TypeEnum.sub; default: throw ArgumentError('无效数值: $json'); } } @override int toJson(TypeEnum object) { // 序列化时选一个业务认可的代表值返回就行 switch (object) { case TypeEnum.add: return 0; case TypeEnum.sub: return 2; } } } // 使用示例 @JsonSerializable() class ExampleModel { @TypeEnumConverter() final TypeEnum type; ExampleModel({required this.type}); factory ExampleModel.fromJson(Map<String, dynamic> json) => _$ExampleModelFromJson(json); Map<String, dynamic> toJson() => _$ExampleModelToJson(this); }
2. 手动写映射方法(无第三方库场景)
如果不用序列化库,直接给枚举加扩展方法处理映射:
enum TypeEnum { add, sub } extension TypeEnumExtension on TypeEnum { // 数值转枚举 static TypeEnum fromInt(int value) { switch (value) { case 0: case 1: case 3: case 9: case 10: case 11: case 12: return TypeEnum.add; case 2: case 4: case 5: case 6: case 7: case 8: return TypeEnum.sub; default: throw ArgumentError('不支持的数值: $value'); } } // 枚举转数值(选一个代表值) int toInt() { switch (this) { case TypeEnum.add: return 0; case TypeEnum.sub: return 2; } } } // 调用示例 void main() { final type = TypeEnumExtension.fromInt(10); print(type); // 输出 TypeEnum.add print(type.toInt()); // 输出 0 }
3. 用映射表实现(更直观的手动方式)
也可以定义静态映射表,把所有数值和枚举的对应关系列出来:
enum TypeEnum { add, sub } extension TypeEnumMap on TypeEnum { static const _intToEnum = <int, TypeEnum>{ 0: TypeEnum.add, 1: TypeEnum.add, 3: TypeEnum.add, 9: TypeEnum.add, 10: TypeEnum.add, 11: TypeEnum.add, 12: TypeEnum.add, 2: TypeEnum.sub, 4: TypeEnum.sub, 5: TypeEnum.sub, 6: TypeEnum.sub, 7: TypeEnum.sub, 8: TypeEnum.sub, }; static TypeEnum fromInt(int value) { return _intToEnum[value] ?? throw ArgumentError('无效数值: $value'); } int get toInt { switch (this) { case TypeEnum.add: return 0; case TypeEnum.sub: return 2; } } }
注意点
- 序列化时,同一个枚举项只能输出一个数值,得根据业务需求选合适的代表值(比如第一个映射值、最常用的数值)。
- 遇到未知数值时,建议抛出异常或者返回默认值,避免隐性bug。
内容的提问来源于stack exchange,提问作者Sara Ghorbani
相关产品推荐
相关产品推荐

