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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:15:34