来自String的枚举

FPG*_*PGA 24 dart

我有一个Enum和一个函数来创建它,String因为我找不到内置的方法来做它

enum Visibility{VISIBLE,COLLAPSED,HIDDEN}

Visibility visibilityFromString(String value){
  return Visibility.values.firstWhere((e)=>
      e.toString().split('.')[1].toUpperCase()==value.toUpperCase());
}

//used as
Visibility x = visibilityFromString('COLLAPSED');
Run Code Online (Sandbox Code Playgroud)

但似乎我必须为每个Enum重写此函数,有没有办法在Enum类型作为参数的情况下编写相同的函数?我试图但我发现我不能投于Enum.

//is something with the following signiture actually possible?
     dynamic enumFromString(Type enumType,String value){

     }
Run Code Online (Sandbox Code Playgroud)

小智 131

从 Dart 版本 2.15 开始,您可以更方便地通过名称查找枚举值,使用.values.byName或 using .values.asNameMap()

enum Visibility {
  visible, collapsed, hidden
}

void main() {
  // Both calls output `true`
  print(Visibility.values.byName('visible') == Visibility.visible);
  print(Visibility.values.asNameMap()['visible'] == Visibility.visible);
}
Run Code Online (Sandbox Code Playgroud)

您可以在官方 Dart 2.15 公告博客文章中阅读有关其他枚举改进的更多信息。

  • 考虑到 Dart 的新版本,这现在应该是正确的答案。 (15认同)

Col*_*son 62

镜子并不总是可用,但幸运的是你不需要它们.这是相当紧凑的,应该做你想要的.

enum Fruit { apple, banana }

// Convert to string
String str = Fruit.banana.toString();

// Convert to enum
Fruit f = Fruit.values.firstWhere((e) => e.toString() == str);

assert(f == Fruit.banana);  // it worked
Run Code Online (Sandbox Code Playgroud)

修复: 正如评论部分中@frostymarvelous所提到的,这是正确的实现:

Fruit f = Fruit.values.firstWhere((e) => e.toString() == 'Fruit.' + str);
Run Code Online (Sandbox Code Playgroud)

  • 从 Dart 2.15 开始,我们现在可以以字符串形式访问枚举值名称(即:`Fruit.apple.name == 'apple'`)并编写:`Fruit f = Fruit.values.firstWhere((e) => e。 name == str);` 而不是 `Fruit f = Fruit.values.firstWhere((e) => e.toString() == 'Fruit.' + str);` (9认同)
  • 警告!你的字符串必须是"Fruit.banana"的形式才能工作 (5认同)
  • Dart 的设计看起来大部分事情都是正确的,但我很惊讶 String 之间的转换并不更优雅;也许将来他们会为此引入一些语法糖? (4认同)
  • 您还可以使用package:flutter / foundation.dart软件包中的describeEnum来摆脱Fruit。`String str =“ banana”; 水果f = Fruit.values.firstWhere((e)=> describeEnum(e)== str);` (3认同)
  • 覆盖意外的字符串值: `firstWhere((e) => e.toString() == 'Fruit.' + str, orElse: () => null);` (3认同)

Rya*_*ell 16

这一切都太复杂了,我制作了一个简单的库来完成工作:

https://pub.dev/packages/enum_to_string

import 'package:enum_to_string:enum_to_string.dart';

enum TestEnum { testValue1 };

convert(){
    String result = EnumToString.parse(TestEnum.testValue1);
    //result = 'testValue1'

    String resultCamelCase = EnumToString.parseCamelCase(TestEnum.testValue1);
    //result = 'Test Value 1'

    final result = EnumToString.fromString(TestEnum.values, "testValue1");
    // TestEnum.testValue1
}
Run Code Online (Sandbox Code Playgroud)


anz*_*ert 14

从 Dart 2.17 开始,您可以使用增强型枚举优雅地解决这个问题。

(参见/sf/answers/4998843321/

只需将静态方法添加到您选择的枚举中,如下所示:

enum Example {
  example1,
  example2,
  example3;

  static Example? fromName(String name) {
    for (Example enumVariant in Example.values) {
      if (enumVariant.name == name) return enumVariant;
    }
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样查找枚举:

Example? test = Example.fromName("example1");
    
print(test);    // returns Example.example1
Run Code Online (Sandbox Code Playgroud)

编辑:

另一位用户发布了一个更好的解决方案,不需要添加静态方法。

只需使用内置方法,如下所示:

Example? test2 = Example.values.asNameMap()["example1"];

print(test2);    // returns Example.example1
Run Code Online (Sandbox Code Playgroud)


Rob*_*ert 11

使用镜子,您可以强制某些行为。我有两个想法。不幸的是Dart不支持类型化函数:

import 'dart:mirrors';

enum Visibility {VISIBLE, COLLAPSED, HIDDEN}

class EnumFromString<T> {
  T get(String value) {
    return (reflectType(T) as ClassMirror).getField(#values).reflectee.firstWhere((e)=>e.toString().split('.')[1].toUpperCase()==value.toUpperCase());
  }
}

dynamic enumFromString(String value, t) {
  return (reflectType(t) as ClassMirror).getField(#values).reflectee.firstWhere((e)=>e.toString().split('.')[1].toUpperCase()==value.toUpperCase());
}

void main() {
  var converter = new EnumFromString<Visibility>();

  Visibility x = converter.get('COLLAPSED');
  print(x);

  Visibility y = enumFromString('HIDDEN', Visibility);
  print(y);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Visibility.COLLAPSED
Visibility.HIDDEN
Run Code Online (Sandbox Code Playgroud)

  • 该代码需要审查,它似乎在当前版本中不起作用 (5认同)

小智 11

使用Dart 2.15,我们现在可以做到这一点,这更加干净

  // Convert to string
  String fruitName = Fruit.banana.name;

  // Convert back to enum
  Fruit fruit = Fruit.values.byName(fruitName);
  print(fruit); // Fruit.banana
  assert(fruit == Fruit.banana);

Run Code Online (Sandbox Code Playgroud)


Kri*_*sta 10

Here is an alternative way to @mbartn's approach using extensions, extending the enum itself instead of String.

Faster, but more tedious

// We're adding a 'from' entry just to avoid having to use Fruit.apple['banana'],
// which looks confusing.
enum Fruit { from, apple, banana }

extension FruitIndex on Fruit {
  // Overload the [] getter to get the name of the fruit.
  operator[](String key) => (name){
    switch(name) {
      case 'banana': return Fruit.banana;
      case 'apple':  return Fruit.apple;
      default:       throw RangeError("enum Fruit contains no value '$name'");
    }
  }(key);
}

void main() {
  Fruit f = Fruit.from["banana"];
  print("$f is ${f.runtimeType}"); // Outputs: Fruit.banana is Fruit
}
Run Code Online (Sandbox Code Playgroud)

Less tedius, but slower

If O(n) performance is acceptable you could also incorporate @Collin Jackson's answer:

// We're adding a 'from' entry just to avoid having to use Fruit.apple['banana']
// which looks confusing.
enum Fruit { from, apple, banana }

extension FruitIndex on Fruit {
  // Overload the [] getter to get the name of the fruit.
  operator[](String key) =>
    Fruit.values.firstWhere((e) => e.toString() == 'Fruit.' + key);
}

void main() {
  Fruit f = Fruit.from["banana"];
  print("$f is ${f.runtimeType}"); // Outputs: Fruit.banana is Fruit
}
Run Code Online (Sandbox Code Playgroud)


Ped*_*usa 9

我使用这个函数,我认为它很简单,不需要任何类型的“黑客”:

T enumFromString<T>(List<T> values, String value) {
    return values.firstWhere((v) => v.toString().split('.')[1] == value,
                             orElse: () => null);
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

enum Test {
    value1,
    value2,
}

var test = enumFromString(Test.value, 'value2') // Test.value2
Run Code Online (Sandbox Code Playgroud)


use*_*613 8

在最新版本的Dart中,enum可以支持自定义字段和方法。因此,最现代的方法是为名称/标签编写自定义字段和静态解析器函数。

例如:

enum Foo {
  a('FIRST'),
  b('SECOND'),
  c('THIRD'),
  unknown('UNKNOWN'); // make sure the last element ends in `;`

  final String label; // define a private field

  const Foo(this.label); // constructor

  static Foo fromString(String label) { // static parser method
    return values.firstWhere(
      (v) => v.label == label,
      orElse: () => Foo.unknown,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

final foo = Foo.fromString('FIRST'); // will get `Foo.a`
Run Code Online (Sandbox Code Playgroud)


Spe*_*cer 6

Collin Jackson的解决方案对我不起作用,因为Dart将枚举字符串化为字符串EnumName.value而不是value(例如Fruit.apple),并且我试图将字符串值转换为类似于apple而不是Fruit.apple从一开始就转换。

考虑到这一点,这是我针对字符串问题枚举的解决方案

enum Fruit {apple, banana}

Fruit getFruitFromString(String fruit) {
  fruit = 'Fruit.$fruit';
  return Fruit.values.firstWhere((f)=> f.toString() == fruit, orElse: () => null);
}
Run Code Online (Sandbox Code Playgroud)

  • 要仅返回“ apple”,请尝试以下操作:Fruit.apple.toString()。split(“。”)[1]; (3认同)

Cop*_*oad 6

你的枚举

enum Day {
  monday,
  tuesday,
}
Run Code Online (Sandbox Code Playgroud)

添加这个扩展(需要一个 import 'package:flutter/foundation.dart';

extension EnumEx on String {
  Day toEnum() => Day.values.firstWhere((d) => describeEnum(d) == toLowerCase());
}
Run Code Online (Sandbox Code Playgroud)

用法:

void main() {
  String s = 'monday'; // String
  Day monday = s.toEnum(); // Converted to enum
}
Run Code Online (Sandbox Code Playgroud)

  • `byName` 是迄今为止最好的解决方案。 (3认同)
  • 这会将枚举转换为字符串。它能够将字符串转换为枚举吗?问题就在于此。 (2认同)

Ram*_*tan 5

我的解决方案与Rob C的解决方案相同,但没有字符串插值:

T getEnumFromString<T>(Iterable<T> values, String value) {
  return values.firstWhere((type) => type.toString().split(".").last == value,
      orElse: () => null);
}
Run Code Online (Sandbox Code Playgroud)


Ham*_*med 5

您可以像下面这样编写getEnumgetEnum将遍历枚举值并返回等于所需字符串的第一个枚举。

Sample getEnum(String name) => Sample.values.firstWhere(
      (v) => v.name.toLowerCase() == name.toLowerCase(),
      orElse: () => throw Exception('Enum value not found.'),
    );

enum SampleEnum { first, second, third }
Run Code Online (Sandbox Code Playgroud)

更新

另外,你可以使用这个:

final SampleEnum nameEnum = SampleEnum.values.byName('second');  // SampleEnum.second
Run Code Online (Sandbox Code Playgroud)

用法:

void main() {
  print(getEnum('first'));
}
Run Code Online (Sandbox Code Playgroud)