Enum from String

前端 未结 18 1973
温柔的废话
温柔的废话 2020-12-15 14:54

I have an Enum and a function to create it from a String because i couldn\'t find a built in way to do it



        
相关标签:
18条回答
  • 2020-12-15 15:32

    I think my approach is slightly different, but might be more convenient in some cases. Finally, we have parse and tryParse for enum types:

    import 'dart:mirrors';
    
    class Enum {
      static T parse<T>(String value) {
        final T result = (reflectType(T) as ClassMirror).getField(#values)
            .reflectee.firstWhere((v)=>v.toString().split('.').last.toLowerCase() == value.toLowerCase()) as T;
        return result;
      }
    
      static T tryParse<T>(String value, { T defaultValue }) {
        T result = defaultValue;
        try {
          result = parse<T>(value);
        } catch(e){
          print(e);
        }
        return result;
      }
    }
    

    EDIT: this approach is NOT working in the Flutter applications, by default mirrors are blocked in the Flutter because it causes the generated packages to be very large.

    0 讨论(0)
  • 2020-12-15 15:33

    Using mirrors you could force some behaviour. I had two ideas in mind. Unfortunately Dart does not support typed functions:

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

    Outputs:

    Visibility.COLLAPSED
    Visibility.HIDDEN
    
    0 讨论(0)
  • 2020-12-15 15:33

    I improved Collin Jackson's answer using Dart 2.7 Extension Methods to make it more elegant.

    enum Fruit { apple, banana }
    
    extension EnumParser on String {
      Fruit toFruit() {
        return Fruit.values.firstWhere(
            (e) => e.toString().toLowerCase() == 'fruit.$this'.toLowerCase(),
            orElse: () => null); //return null if not found
      }
    }
    
    main() {
      Fruit apple = 'apple'.toFruit();
      assert(apple == Fruit.apple); //true
    }
    
    0 讨论(0)
  • 2020-12-15 15:35

    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
    }
    

    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
    }
    
    0 讨论(0)
  • 2020-12-15 15:40

    I had the same problem in one of my projects and existing solutions were not very clean and it didn't support advanced features like json serialization/deserialization.

    Flutter natively doesn't currently support enum with values, however, I managed to develop a helper package Vnum using class and reflectors implementation to overcome this issue.

    Address to the repository:

    https://github.com/AmirKamali/Flutter_Vnum

    To answer your problem using Vnum, you could implement your code as below:

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

    You can use it like :

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

    There's more documentation in the github repo, hope it helps you out.

    0 讨论(0)
  • 2020-12-15 15:41
        enum HttpMethod { Connect, Delete, Get, Head, Options, Patch, Post, Put, Trace }
    
        HttpMethod httpMethodFromString({@required String httpMethodName}) {
        assert(httpMethodName != null);
    
        if (httpMethodName is! String || httpMethodName.isEmpty) {
          return null;
        }
    
        return HttpMethod.values.firstWhere(
          (e) => e.toString() == httpMethodName,
          orElse: () => null,
        );
      }
    
    0 讨论(0)
提交回复
热议问题