如何获得枚举的名称作为字符串

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

例如,当我想要的是“ MONDAY”时,每种情况下小测试代码片段都返回“ day.MONDAY”

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

为了得到“ MONDAY”,我需要解析字符串,对吗?

139537 次浏览

遗憾的是,toString 方法返回的是 "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>注释,以表明不需要类名重复。

获取枚举名称的最简单方法是来自 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 序列化/反序列化这样的高级特性。

Flutter 本身目前不支持带值的枚举,但是,我设法使用类和反射器实现开发了一个帮助程序包 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 repo 中有更多的文档,希望它能帮到你。

Dart 2.7有一个新的特性叫做 扩展方法。现在您可以为 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 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版本 博客文章中详细阅读所有 enum改进。

从 dart 2.15开始,您可以使用 .name来获得 enum 元素的名称。

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');

省道版本 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
...

当然,你可以把你需要的任何类型。

通过 Dart 2.17,我们现在对枚举上的成员有了普遍的支持。这意味着我们可以添加保存状态的字段、设置状态的构造函数、具有功能性的方法,甚至可以覆盖现有成员。

例如:

enum Day {
MONDAY("Monday"),
TUESDAY("Tuesday");


const Day(this.text);
final String text;
}

产出:

void main() {
const day = Day.MONDAY;
print(day.text); /// Monday
}

对于以上功能覆盖省道版本,如下面的目标2.17和更高

environment:
sdk: ">=2.17.0 <3.0.0"

因为 Dart 2.15只用“ . name”

enum day {monday, tuesday}
print( 'Today is ${day.monday.name}');