Enum from String

Dart

Dart Problem Overview


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

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


 

but it seems like i have to rewrite this function for every Enum i have, is there a way to write the same function where it takes the Enum type as parameter? i tried to but i figured out that i can't cast to Enum.

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

Dart Solutions


Solution 1 - Dart

Mirrors aren't always available, but fortunately you don't need them. This is reasonably compact and should do what you want.

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

Fix: As mentioned by @frostymarvelous in the comments section, this is correct implementation:

Fruit f = Fruit.values.firstWhere((e) => e.toString() == 'Fruit.' + str);

Solution 2 - Dart

My solution is identical to Rob C's solution but without string interpolation:

T enumFromString<T>(Iterable<T> values, String value) {
  return values.firstWhere((type) => type.toString().split(".").last == value,
      orElse: () => null);
}

Null safe example using firstWhereOrNull() from the collection package

static T? enumFromString<T>(Iterable<T> values, String value) {
  return values.firstWhereOrNull((type) => type.toString().split(".").last == value);
}

Solution 3 - Dart

This is all so complicated I made a simple library that gets the job done:

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
}

Update: 2022/02/10 Dart v2.15 has implemented some additional enum methods that may solve your problems.

From here: https://medium.com/dartlang/dart-2-15-7e7a598e508a

Improved enums in the dart:core library

We’ve made a number of convenience additions to the enum APIs in the dart:core library (language issue #1511). You can now get the String value for each enum value using .name:

enum MyEnum {
  one, two, three
}
void main() {
  print(MyEnum.one.name);  // Prints "one".
}

You can also look up an enum value by name:

print(MyEnum.values.byName('two') == MyEnum.two);  // Prints "true".

Finally, you can get a map of all name-value pairs:

final map = MyEnum.values.asNameMap(); 
print(map['three'] == MyEnum.three);  // Prints "true".

Solution 4 - Dart

As from Dart version 2.15, you can lookup an enum value by name a lot more conveniently, using .values.byName or 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);
}

You can read more about other enum improvements in the official Dart 2.15 announcement blog post.

Solution 5 - Dart

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

Solution 6 - Dart

Collin Jackson's solution didn't work for me because Dart stringifies enums into EnumName.value rather than just value (for instance, Fruit.apple), and I was trying to convert the string value like apple rather than converting Fruit.apple from the get-go.

With that in mind, this is my solution for the enum from string problem

enum Fruit {apple, banana}

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

Solution 7 - Dart

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
}

Solution 8 - Dart

I use this function, I think it's simple and doesn't need any kind of 'hack':

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

You can use it like this:

enum Test {
    value1,
    value2,
}

var test = enumFromString(Test.value, 'value2') // Test.value2

Solution 9 - Dart

Update:
void main() {
  Day monday = Day.values.byName('monday'); // This is all you need
}

enum Day {
  monday,
  tuesday,
}

Old solution:

Your enum

enum Day {
  monday,
  tuesday,
}

Add this extension (need a import 'package:flutter/foundation.dart';)

extension EnumEx on String {
  Day toEnum() => Day.values.firstWhere((d) => describeEnum(d) == toLowerCase());
}

Usage:

void main() {
  String s = 'monday'; // String
  Day monday = s.toEnum(); // Converted to enum
}

Solution 10 - Dart

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
}

Solution 11 - Dart

With Dart 2.15 we can now do this which is much cleaner

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

Solution 12 - Dart

I had the same problem with building objects from JSON. In JSON values are strings, but I wanted enum to validate if the value is correct. I wrote this helper which works with any enum, not a specified one:

class _EnumHelper {


 var cache = {};

  dynamic str2enum(e, s) {
    var o = {};
    if (!cache.containsKey(e)){
      for (dynamic i in e) {
        o[i.toString().split(".").last] = i;
      }
      cache[e] = o;
    } else {
      o = cache[e];
    }
    return o[s];
  }
}

_EnumHelper enumHelper = _EnumHelper();

Usage:

enumHelper.str2enum(Category.values, json['category']);

PS. I did not use types on purpose here. enum is not type in Dart and treating it as one makes things complicated. Class is used solely for caching purposes.

Solution 13 - Dart

Simplified version:

import 'package:flutter/foundation.dart';

static Fruit? valueOf(String value) {
    return Fruit.values.where((e) => describeEnum(e) == value).first;
}

Using the method describeEnum helps you to avoid the usage of the split to get the name of the element.

Solution 14 - Dart

There are a couple of enums packages which allowed me to get just the enum string rather than the type.value string (Apple, not Fruit.Apple).

https://pub.dartlang.org/packages/built_value (this is more up to date)

https://pub.dartlang.org/packages/enums

void main() {
  print(MyEnum.nr1.index);            // prints 0
  print(MyEnum.nr1.toString());       // prints nr1
  print(MyEnum.valueOf("nr1").index); // prints 0
  print(MyEnum.values[1].toString())  // prints nr2
  print(MyEnum.values.last.index)     // prints 2
  print(MyEnum.values.last.myValue);  // prints 15
}  

Solution 15 - Dart

Here is the function that converts given string to enum type:

EnumType enumTypeFromString(String typeString) => EnumType.values
    .firstWhere((type) => type.toString() == "EnumType." + typeString);

And here is how you convert given enum type to string:

String enumTypeToString(EnumType type) => type.toString().split(".")[1];

Solution 16 - Dart

Generalising @CopsOnRoad's solution to work for any enum type,

enum Language { en, ar }

extension StringExtension on String {
   T toEnum<T>(List<T> list) => list.firstWhere((d) => d.toString() == this);
}

String langCode = Language.en.toString();
langCode.toEnum(Language.values);

Solution 17 - Dart

@Collin Jackson has a very good answer IMO. I had used a for-in loop to achieve a similar result prior to finding this question. I am definitely switching to using the firstWhere method.

Expanding on his answer this is what I did to deal with removing the type from the value strings:

enum Fruit { apple, banana }

class EnumUtil {
    static T fromStringEnum<T>(Iterable<T> values, String stringType) {
        return values.firstWhere(
                (f)=> "${f.toString().substring(f.toString().indexOf('.')+1)}".toString()
                    == stringType, orElse: () => null);
    }
}

main() {
    Fruit result = EnumUtil.fromStringEnum(Fruit.values, "apple");
    assert(result == Fruit.apple);
}

Maybe someone will find this useful...

Solution 18 - Dart

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.

Solution 19 - Dart

enum Fruit { orange, apple }

// Waiting for Dart static extensions
// Issue https://github.com/dart-lang/language/issues/723
// So we will be able to Fruit.parse(...)
extension Fruits on Fruit {
  static Fruit? parse(String raw) {
    return Fruit.values
        .firstWhere((v) => v.asString() == raw, orElse: null);
  }

  String asString() {
    return this.toString().split(".").last;
  }
}
...
final fruit = Fruits.parse("orange"); // To enum
final value = fruit.asString(); // To string

Solution 20 - Dart

Generalizing on @Pedro Sousa's excellent solution, and using the built-in describeEnum function:

extension StringExtension on String {
  T toEnum<T extends Object>(List<T> values) {
    return values.singleWhere((v) => this.equalsIgnoreCase(describeEnum(v)));
  }
}

Usage:

enum TestEnum { none, test1, test2 }
final testEnum = "test1".toEnum(TestEnum.values);
expect(testEnum, TestEnum.test1);

Solution 21 - Dart

Since Dart 2.17 you can solve this elegantly with Enhanced Enums.

(see https://stackoverflow.com/a/71412047/15760132 )

Just add a static method to your enum of choice, like this:

enum Example {
  example1,
  example2,
  example3;

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

Then you can look for the enum like this:

Example? test = Example.fromName("example1");
    
print(test);    // returns Example.example1

Solution 22 - Dart

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.

Solution 23 - Dart

enum in Dart just has too many limitations. The extension method could add methods to the instances, but not static methods.

I really wanted to be able to do something like MyType.parse(myString), so eventually resolved to use manually defined classes instead of enums. With some wiring, it is almost functionally equivalent to enum but could be modified more easily.

class OrderType {
  final String string;
  const OrderType._(this.string);

  static const delivery = OrderType._('delivery');
  static const pickup = OrderType._('pickup');

  static const values = [delivery, pickup];

  static OrderType parse(String value) {
    switch (value) {
      case 'delivery':
        return OrderType.delivery;
        break;
      case 'pickup':
        return OrderType.pickup;
        break;
      default:
        print('got error, invalid order type $value');
        return null;
    }
  }

  @override
  String toString() {
    return 'OrderType.$string';
  }
}

// parse from string
final OrderType type = OrderType.parse('delivery');
assert(type == OrderType.delivery);
assert(type.string == 'delivery');

Solution 24 - Dart

another variant, how it might be solved:

enum MyEnum {
  value1,
  value2,
}

extension MyEnumX on MyEnum {
  String get asString {
    switch (this) {
      case MyEnum.value1:
        return _keyValue1;
      case MyEnum.value2:
        return _keyValue2;
    }
    throw Exception("unsupported type");
  }

  MyEnum fromString(String string) {
    switch (string) {
      case _keyValue1:
        return MyEnum.value1;
      case _keyValue2:
        return MyEnum.value2;
    }
    throw Exception("unsupported type");
  }
}

const String _keyValue1 = "value1";
const String _keyValue2 = "value2";

void main() {
    String string = MyEnum.value1.asString;
    MyEnum myEnum = MyEnum.value1.fromString(string);
}

Solution 25 - Dart

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

Solution 26 - Dart

When migrating to null-safety, the Iterable.firstWhere method no longer accepts orElse: () => null. Here is the implementation considering the null-safety:

import 'package:collection/collection.dart';

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

T? enumFromString<T>(String key, List<T> values) => values.firstWhereOrNull((v) => key == enumToString(v!));

Solution 27 - Dart

You can do something like this:

extension LanguagePreferenceForString on String {
LanguagePreferenceEntity toLanguagePrerence() {
switch (this) {
  case "english":
    return LanguagePreferenceEntity.english;
  case "turkish":
    return LanguagePreferenceEntity.turkish;
  default:
    return LanguagePreferenceEntity.english;
  }
 }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFPGAView Question on Stackoverflow
Solution 1 - DartCollin JacksonView Answer on Stackoverflow
Solution 2 - DartRambutanView Answer on Stackoverflow
Solution 3 - DartRyan KnellView Answer on Stackoverflow
Solution 4 - DartPéter GyarmatiView Answer on Stackoverflow
Solution 5 - DartRobertView Answer on Stackoverflow
Solution 6 - DartSpencerView Answer on Stackoverflow
Solution 7 - DartKristaView Answer on Stackoverflow
Solution 8 - DartPedro SousaView Answer on Stackoverflow
Solution 9 - DartCopsOnRoadView Answer on Stackoverflow
Solution 10 - DartmbartnView Answer on Stackoverflow
Solution 11 - Darteyedea_abilityView Answer on Stackoverflow
Solution 12 - DartAdrian KalbarczykView Answer on Stackoverflow
Solution 13 - DartTiarê BalbiView Answer on Stackoverflow
Solution 14 - DartatreeonView Answer on Stackoverflow
Solution 15 - DartUgurcan YildirimView Answer on Stackoverflow
Solution 16 - DartAbdul RahmanView Answer on Stackoverflow
Solution 17 - DartRob CView Answer on Stackoverflow
Solution 18 - DartAmir.n3tView Answer on Stackoverflow
Solution 19 - DartCaio SantosView Answer on Stackoverflow
Solution 20 - DartJonathan MonsonegoView Answer on Stackoverflow
Solution 21 - DartanzbertView Answer on Stackoverflow
Solution 22 - DartNET3View Answer on Stackoverflow
Solution 23 - DartEdwin LiuView Answer on Stackoverflow
Solution 24 - DartAndriy AntonovView Answer on Stackoverflow
Solution 25 - DartTeeTrackerView Answer on Stackoverflow
Solution 26 - DartTaiyr BegeyevView Answer on Stackoverflow
Solution 27 - DartbatuhankrbbView Answer on Stackoverflow