Dart 如何将枚举的名称作为字符串获取

Dart How to get the name of an enum as a String

在枚举在 Dart 中可用之前,我写了一些繁琐且难以维护的代码来模拟枚举,现在想简化它。我需要将枚举的名称作为字符串获取,例如可以使用 Java 但不能。

例如小测试代码片段 returns 'day.MONDAY' 在每种情况下我想要的是“星期一”

enum day {MONDAY, TUESDAY}
print( 'Today is $day.MONDAY');
print( 'Today is $day.MONDAY.toString()');

我是否更正了 'MONDAY' 我需要解析字符串?

遗憾的是,您是正确的,toString 方法 returns "day.MONDAY",而不是更有用的 "MONDAY"。 您可以获得字符串的其余部分:

day theDay = day.MONDAY;      
print(theDay.toString().substring(theDay.toString().indexOf('.') + 1));

诚然,不太方便。

另一种将枚举名称作为字符串获取的方法是:

theDay.toString().split('.').last

如果性能不重要,那可能就是我要写的内容,只是为了简洁。

如果要迭代所有值,可以使用 day.values:

for (day theDay in day.values) {
  print(theDay);
}

短一点:

String day = theDay.toString().split('.').last;

还有一个更优雅的解决方案:

enum SomeStatus {
  element1,
  element2,
  element3,
  element4,
}

const Map<SomeStatus, String> SomeStatusName = {
  SomeStatus.element1: "Element 1",
  SomeStatus.element2: "Element 2",
  SomeStatus.element3: "Element 3",
  SomeStatus.element4: "Element 4",
};

print(SomeStatusName[SomeStatus.element2]) // prints: "Element 2"

我使用如下结构:

abstract class Strings {
  static const angry = "Dammit!";
  static const happy = "Yay!";
  static const sad = "QQ";
}

我的方法并没有根本不同,但在某些情况下可能会稍微方便一些:

enum Day {
  monday,
  tuesday,
}

String dayToString(Day d) {
  return '$d'.split('.').last;
}

在 Dart 中,您不能自定义枚举的 toString 方法,所以我认为这个辅助函数解决方法是必要的,它是最好的方法之一。如果你想在这种情况下更正确,你可以将返回的字符串的第一个字母大写。

您还可以添加一个 dayFromString 函数

Day dayFromString(String s) {
  return Day.values.firstWhere((v) => dayToString(v) == s);
}

用法示例:

void main() {
  Day today = Day.monday;
  print('Today is: ${dayToString(today)}');
  Day tomorrow = dayFromString("tuesday");
  print(tomorrow is Day);
}

我使用以下函数获取枚举值的名称,反之亦然,通过名称获取枚举值:

String enumValueToString(Object o) => o.toString().split('.').last;

T enumValueFromString<T>(String key, Iterable<T> values) => values.firstWhere(
      (v) => v != null && key == enumValueToString(v),
      orElse: () => null,
    );

当使用 Dart 2.7 和更新版本时,扩展方法可以在这里工作(以及任何其他对象):

extension EnumX on Object {
  String asString() => toString().split('.').last;
}

上面的实现不依赖于特定的枚举。

使用示例:

enum Fruits {avocado, banana, orange}
...
final banana = enumValueFromString('banana', Fruits.values);
print(enumValueToString(banana)); // prints: "banana"
print(banana.asString()); // prints: "banana"

2020-04-05 编辑: 添加了可空性检查。 values 参数可以是 Iterable,不一定是 List。添加了扩展方法实现。从示例中删除了 <Fruits> 注释以表明不需要 class 名称重复。

获取枚举名称的最简单方法是 flutter/foundation.dart

中的标准方法
describeEnum(enumObject)

enum Day {
  monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

void validateDescribeEnum() {
  assert(Day.monday.toString() == 'Day.monday');
  assert(describeEnum(Day.monday) == 'monday');
}

我受够了,我做了一个包:

https://pub.dev/packages/enum_to_string

还有一个方便的函数,它接受 enum.ValueOne 并将其解析为“Value one

它是一个简单的小库,但经过了单元测试,我欢迎为边缘情况添加任何内容。

我在我的一个项目中遇到了同样的问题,现有的解决方案不是很干净,也不支持像 json serialization/deserialization 这样的高级功能。

Flutter 目前本身不支持带值的枚举,但是,我设法使用 class 和反射器实现开发了一个帮助程序包 Vnum 来克服这个问题。

存储库地址:

https://github.com/AmirKamali/Flutter_Vnum

要使用 Vnum 回答您的问题,您可以按如下方式实现您的代码:

@VnumDefinition
class Visibility extends Vnum<String> {
  static const VISIBLE = const Visibility.define("VISIBLE");
  static const COLLAPSED = const Visibility.define("COLLAPSED");
  static const HIDDEN = const Visibility.define("HIDDEN");

  const Visibility.define(String fromValue) : super.define(fromValue);
  factory Visibility(String value) => Vnum.fromValue(value,Visibility);
}

你可以这样使用它:

var visibility = Visibility('COLLAPSED');
print(visibility.value);

github 存储库中有更多文档,希望对您有所帮助。

Dart 2.7 带有名为 Extension methods 的新功能。现在您可以为 Enum 编写自己的方法,就这么简单!

enum Day { monday, tuesday }

extension ParseToString on Day {
  String toShortString() {
    return this.toString().split('.').last;
  }
}

main() {
  Day monday = Day.monday;
  print(monday.toShortString()); //prints 'monday'
}

我们可以在对象上定义扩展并从任何枚举访问 .enumValue,而不是为每个枚举定义扩展。

void main() {

  // ❌ Without Extension ❌

  print(Countries.Cote_d_Ivoire.toString().split('.').last.replaceAll("_", " ")); // Cote d Ivoire
  print(Movies.Romance.toString().split('.').last.replaceAll("_", " ")); //Romance


  // ✅ With Extension ✅

  print(Countries.Cote_d_Ivoire.enumValue); // Cote d Ivoire
  print(Movies.Romance.enumValue); //Romance
}

enum Countries { United_States, United_Kingdom, Germany, Japan, Cote_d_Ivoire }
enum Movies { Romance, Science_Fiction, Romantic_Comedy, Martial_arts }

extension PrettyEnum on Object {
  String get enumValue => this.toString().split('.').last.replaceAll("_", " ");
}

有了这个,你甚至可以定义多词枚举,其中单词在其名称中由 _(下划线)分隔。

enum day {MONDAY, TUESDAY}
print(day.toString().split('.')[1]);
OR
print(day.toString().split('.').last);

更新 Dart 2.15:

enum Day {
  monday,
  tuesday,
}

您可以在枚举上使用 name 属性。

String monday = Day.monday.name; // 'monday'

旧解决方案:

1.直接方式:

var dayInString = describeEnum(Day.monday);
print(dayInString); // prints 'monday'

2。使用扩展名:

extension DayEx on Day {
  String get name => describeEnum(this);
}

您可以像这样使用它:

void main() {
  Day monday = Day.monday;
  print(monday.name); // 'monday'
}
enum day {MONDAY, TUESDAY}
print( 'Today is ${describeEnum(day.MONDAY)}' );

控制台输出:今天是星期一

创建一个class来帮助:

class Enum {
    Enum._();

    static String name(value) {
        return value.toString().split('.').last;
    }
}

并调用:

Enum.name(myEnumValue);

有时我需要将ui-value 和real-value 分开,所以我使用Map 定义键和值。这样,我们就有了更多的灵活性。通过使用 extension(自 Dart 2.7 起),我创建了一个读取其键和值的方法。

enum Status {
  progess,
  done,
}

extension StatusExt on Status {
  static const Map<Status, String> keys = {
    Status.progess: 'progess',
    Status.done: 'done',
  };

  static const Map<Status, String> values = {
    Status.progess: 'In Progress',
    Status.done: 'Well done',
  };

  String get key => keys[this];
  String get value => values[this];

  // NEW
  static Status fromRaw(String raw) => keys.entries
      .firstWhere((e) => e.value == raw, orElse: () => null)
      ?.key;
}

// usage 1
Status status = Status.done;
String statusKey = status.key; // done
String statusValue = status.value; // Well done

// usage 2 (easy to make key and value list)
List<Status> statuses = Status.values;
List<String> statusKeys = statuses.map((e) => e.key).toList();
List<String> statusValues = statuses.map((e) => e.value).toList();

// usage 3. create Status enum from string.
Status done1 = StatusExt.fromRaw('done') // Status.done
Status done2 = StatusExt.fromRaw('dude') // null

现在空安全看起来像这样

String enumToString(Object? o) => o != null ? o.toString().split('.').last : '';


T? enumFromString<T>(String key, List<T> values) {
  try {
    return values.firstWhere((v) => key == enumToString(v));
  } catch(e) {
    return null;
  }
}

你可以看看这个包enum_object

// convert enum value to string
print(TestEnum.test.enumValue);

// convert String to enum value
var enumObject = EnumObject<TestEnum>(TestEnum.values);
print(enumObject.enumFromString('test2'));```

还有一种方法:

enum Length {
  TEN,
  TWENTY,
  THIRTY,
  NONE,
}

extension LengthValue on Length {
  static const _values = [10, 20, 30, 0];

  int get value => _values[this.index];
}

我在答案中找到的一个好方法是

String day = theDay.toString().split('.').last;

但我不建议这样做,因为 dart 为我们提供了更好的方法。

为枚举定义一个扩展名,可能在与以下文件相同的文件中:

enum Day {
  monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

extension DayExtension on Day {
  String get value => describeEnum(this);
}

你需要为此做 import 'package:flutter/foundation.dart';

Dart 2.15 包含一个扩展来简化此操作:

enum day {MONDAY, TUESDAY}
print( 'Today is ${day.MONDAY.name}');

https://github.com/dart-lang/sdk/commit/18f37dd8f3db6486f785b2c42a48dfa82de0948b 中的更改推出稳定版本的 Dart 之前,此处其他聪明但更复杂的答案非常有用。

试试这个解决方案:

extension EnumValueToString on Enum {
  String valueAsString() {
    return describeEnum(this);
  }
}

使用方法:

enum.valueAsString()

dart 2.15 现在支持这个 你可以输入

print(day.MONDAY.name); //gives you: MONDAY

从 Dart 2.15 开始,我们可以只做 Day.monday.name,其中

enum Day { monday, tuesday }

从 Dart 版本 2.15 开始,您可以使用 .name:

访问 enum 常量的 String
enum day {MONDAY, TUESDAY}

void main() {
  print('Today is ${day.MONDAY.name}');
  // Outputs: Today is MONDAY
}

您可以详细阅读官方 Dart 2.15 版本 blog post 中的所有 enum 改进 blog post

从 dart 2.15 开始,您可以使用 .name 获取枚举元素的名称。

enum day {MONDAY, TUESDAY}
print(day.MONDAY.name); // prints MONDAY

从 Dart 2.15 开始,您可以从

获取枚举值
print(MyEnum.one.name);
// and for getting enum from value you use
print(MyEnum.values.byName('two');

Dart 版本 2.15 在枚举上引入了 name 属性。

示例

void main() {
  MyEnum.values.forEach((e) => print(e.name));
}

enum MyEnum { value1, Value2, VALUE2 }

输出:

value1
Value2
VALUE2

对于需要带值枚举的用户,请使用此方法,因为 Dart 不支持此方法:

class MyEnumClass {
  static String get KEY_1 => 'value 1';
  static String get KEY_2 => 'value 2';
  static String get KEY_3 => 'value 3';
  ...
}

// Usage:
print(MyEnumClass.KEY_1); // value 1
print(MyEnumClass.KEY_2); // value 2
print(MyEnumClass.KEY_3); // value 3
...

当然你可以输入你需要的任何类型。