【问题标题】:Dart How to get the name of an enum as a StringDart 如何获取枚举的“值”
【发布时间】:2015-06-16 12:21:51
【问题描述】:

在 Dart 中提供枚举之前,我编写了一些繁琐且难以维护的代码来模拟枚举,现在想对其进行简化。我需要将枚举的值作为字符串获取,例如可以用 Java 完成但不能。

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

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

我是否更正了只需要解析字符串的“MONDAY”?

【问题讨论】:

标签: enums dart


【解决方案1】:

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'
}

【讨论】:

  • 如此处所述,尽管枚举已正确导入,但我无法使用其他文件的扩展名。当我按照文档示例并向扩展名添加一个名称时,它起作用了:“扩展日格式化”。如果不只是我,也许有一个编辑。还应使用 Jannie 和 mbartn 响应的组合来更新响应。
  • 我恢复了上次的编辑更改,因为没有扩展名就无法使用
  • 这不是最好的解决方案。 Kalpesh Dabhi 在这里提供了一个更好的:stackoverflow.com/a/60615370/9695154
  • describeEnum 是 Fl​​utter 唯一的方法,问题是在 Dart 中获取枚举的值
  • @mbartn Flutter 的实现显示在api.flutter.dev/flutter/foundation/describeEnum.html
【解决方案2】:

短一点:

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

【讨论】:

  • 更简单的方法:theDay.toString().split('.').last
  • 谢谢,@Hani!您的改进既简单又“更安全”。更新了答案。
【解决方案3】:

遗憾的是,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);
}

【讨论】:

  • 旧方式枚举stackoverflow.com/questions/15854549 提供了更大的灵活性,但不能用作常量。创建一个库并使用前缀导入它可以解决此问题(请参阅上面stackoverflow.com/a/15855913/217408 的划线问题中的此答案)。
  • 使用“枚举类”实例作为常量有什么问题?
  • 创建类的 const 实例并将它们用作静态 const 成员应该没有任何问题 - 这就是语言枚举实现所做的事情:class MyEnum { static const MyEnum someItem = const MyEnum(0); static const MyEnum someOtherItem = const MyEnum(1); final int id; const MyEnum(this.id); }
  • @Irm 我能够重写和测试一些我需要的方法。也许有一天枚举会被扩展以提供名称作为字符串。
  • @lrn 我试过了,它奏效了。感谢您指出了这一点。我上次尝试时在doSomething1([Status status = Status.off]) { DartPad 遇到错误
【解决方案4】:

获取枚举名称的最简单方法是来自 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');
}

【讨论】:

【解决方案5】:

更新 Dart 2.15:

enum Day {
  monday,
  tuesday,
}

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

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

旧解决方案:

直接方式:

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

使用扩展:

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

你可以像这样使用它:

void main() {
  Day monday = Day.monday;
  print(monday.name); // 'monday'
}

【讨论】:

  • 利用describeEnum 是必经之路。使用扩展是一个很好的奖励
  • 值得注意的是,describeEnum 是一种只能通过 Flutter 框架使用的方法。所以对于那些想要在香草飞镖中做同样事情的人来说并不理想。
【解决方案6】:

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

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"

【讨论】:

  • 你说它优雅吗?如何?通过在内存中添加额外的空间和 20 行新行?
  • 这实际上是一种反模式。当您需要向枚举添加更多值时,您需要在两个地方修改代码,因为您也应该修改映射。想象一下,如果您在一个大型应用程序中有数百个枚举,并在应用程序的不同部分为它们提供数百个地图。很难维护。
  • 我真的很喜欢这个。其他解决方案似乎很老套。
  • 如果你使用 JsonSerializable 这个 Map 可以由它自动生成。由于大多数现实世界的项目都需要使用某种 JSON 解析器,我认为这是最好的解决方案。其他人则依赖于 enum.toString() 的实现细节,其中包含一个点。
【解决方案7】:
enum day {MONDAY, TUESDAY}
print( 'Today is ${describeEnum(day.MONDAY)}' );

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

【讨论】:

    【解决方案8】:

    有时我需要将 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
    

    【讨论】:

      【解决方案9】:

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

      https://pub.dev/packages/enum_to_string

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

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

      【讨论】:

        【解决方案10】:

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

        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。添加了扩展方法实现。从示例中删除了&lt;Fruits&gt; 注释以表明不需要类名重复。

        【讨论】:

        • 感谢亚历山大的分享!这正是我在我的情况下寻找的;-)
        • 交易枚举的最佳答案
        【解决方案11】:

        我使用如下结构:

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

        【讨论】:

        • 使用abstract 使其无法启动,因为您没有理由要实例化此类
        【解决方案12】:

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

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

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

        【讨论】:

          【解决方案13】:

          另一种方式:

          enum Length {
            TEN,
            TWENTY,
            THIRTY,
            NONE,
          }
          
          extension LengthValue on Length {
            static const _values = [10, 20, 30, 0];
          
            int get value => _values[this.index];
          }
          

          【讨论】:

            【解决方案14】:

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

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

            【讨论】:

              【解决方案15】:

              创建一个类来帮助:

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

              然后调用:

              Enum.name(myEnumValue);
              

              【讨论】:

              • 该类添加了哪些普通方法无法实现的功能?
              【解决方案16】:

              我在我的一个项目中遇到了同样的问题,现有的解决方案不是很干净,它不支持 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 中有更多文档,希望对您有所帮助。

              【讨论】:

                【解决方案17】:
                enum day {MONDAY, TUESDAY}
                print(day.toString().split('.')[1]);
                OR
                print(day.toString().split('.').last);
                

                【讨论】:

                  【解决方案18】:

                  我们可以在对象上定义扩展名并从任何枚举中访问.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("_", " ");
                  }
                  

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

                  【讨论】:

                    【解决方案19】:

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

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

                    【讨论】:

                      【解决方案20】:

                      从 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 的所有改进。

                      【讨论】:

                        【解决方案21】:

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

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

                        【讨论】:

                          【解决方案22】:

                          现在有了 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;
                            }
                          }
                          

                          【讨论】:

                            【解决方案23】:

                            你可以看看这个包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'));```
                            

                            【讨论】:

                            • 从 Dart 2.15 开始,您可以从中获取枚举值; print(MyEnum.one.name); 并从您使用的值中获取枚举; print(MyEnum.values.byName('two')
                            【解决方案24】:

                            试试这个解决方案:

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

                            使用方法:

                            enum.valueAsString()
                            

                            【讨论】:

                              【解决方案25】:

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

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

                              【讨论】:

                                【解决方案26】:

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

                                enum Day { monday, tuesday }
                                

                                【讨论】:

                                  【解决方案27】:

                                  从 Dart 2.15 开始,您可以从中获取枚举值

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

                                  【讨论】:

                                    【解决方案28】:

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

                                    例子

                                    void main() {
                                      MyEnum.values.forEach((e) => print(e.name));
                                    }
                                    
                                    enum MyEnum { value1, Value2, VALUE2 }
                                    

                                    输出:

                                    value1
                                    Value2
                                    VALUE2
                                    

                                    【讨论】:

                                      猜你喜欢
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2019-08-23
                                      • 2014-02-02
                                      • 2017-08-01
                                      • 1970-01-01
                                      • 2022-11-12
                                      相关资源
                                      最近更新 更多