Перечисление из строки
У меня есть 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');
но кажется, что я должен переписать эту функцию для каждого Enum я have, есть ли способ записать ту же функцию, где в качестве параметра используется тип Enum? я попытался, но я понял, что я не могу использовать Enum.
//is something with the following signiture actually possible?
dynamic enumFromString(Type enumType,String value){
}
Ответы
Ответ 1
Использование зеркал может привести к некоторому поведению. У меня было две идеи. К сожалению, 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);
}
Выходы:
Visibility.COLLAPSED
Visibility.HIDDEN
Ответ 2
Зеркала не всегда доступны, но, к счастью, они вам не нужны. Это достаточно компактно и должно делать то, что вы хотите.
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
Исправление: Как упомянуто @frostymarvelous в разделе комментариев, это правильная реализация:
Fruit f = Fruit.values.firstWhere((e) => e.toString() == 'Fruit.' + str);
Ответ 3
Решение Collin Jackson не работает для меня, потому что Dart строит перечисления в EnumName.value
а не просто value
(например, Fruit.apple
), и я пытался преобразовать значение строки, например apple
а не преобразовывать Fruit.apple
из get -идти.
Имея это в виду, это мое решение для перечисления из строковой задачи
enum Fruit {apple, banana}
Fruit getFruitFromString(String fruit) {
fruit = 'Fruit.$fruit';
return Fruit.values.firstWhere((f)=> f.toString() == fruit, orElse: () => null);
}
Ответ 4
Есть несколько пакетов перечислений, которые позволили мне получить только строку перечисления, а не строку type.value(Apple, а не Fruit.Apple).
https://pub.dartlang.org/packages/built_value (это более актуально)
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
}
Ответ 5
У меня была такая же проблема с созданием объектов из JSON. В значениях JSON есть строки, но я хотел, чтобы enum проверял правильность значения. Я написал этот помощник, который работает с любым перечислением, а не с указанным:
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();
Использование:
enumHelper.str2enum(Category.values, json['category']);
PS. Здесь я не использовал типы. enum не является типом в Дарт и рассматривается как сложный процесс. Класс используется исключительно для кеширования.
Ответ 6
Мое решение идентично решению Rob C, но без интерполяции строк:
T getEnumFromString<T>(Iterable<T> values, String value) {
return values.firstWhere((type) => type.toString().split(".").last == value,
orElse: () => null);
}
Ответ 7
@Collin Jackson имеет очень хороший ответ IMO. Я использовал цикл for-in для достижения аналогичного результата до поиска этого вопроса. Я определенно переключаюсь на использование метода firstWhere.
Расширение его ответа - вот что я сделал для устранения типа из строк значений:
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);
}
Может быть, кто-то найдет это полезным...
Ответ 8
Вот функция, которая преобразует данную строку в тип enum:
EnumType enumTypeFromString(String typeString) => EnumType.values
.firstWhere((type) => type.toString() == "EnumType." + typeString);
А вот как вы конвертируете данный тип перечисления в строку:
String enumTypeToString(EnumType type) => type.toString().split(".")[1];
Ответ 9
Я думаю, что мой подход немного отличается, но в некоторых случаях может быть более удобным. Наконец, у нас есть parse и tryParse для перечислимых типов:
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;
}
}
РЕДАКТИРОВАТЬ: этот подход НЕ работает в приложениях Flutter, по умолчанию зеркала заблокированы в Flutter, потому что это приводит к тому, что сгенерированные пакеты будут очень большими.
Ответ 10
У меня была такая же проблема в одном из моих проектов, и существующие решения были не очень чистыми, и он не поддерживал расширенные функции, такие как сериализация/десериализация json.
Flutter изначально не поддерживает enum со значениями, однако мне удалось разработать вспомогательный пакет Vnum
с использованием реализации класса и отражателей для решения этой проблемы.
Обратитесь в хранилище:
https://github.com/AmirKamali/Flutter_Vnum
Чтобы ответить на вашу проблему с помощью 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 есть больше документации, надеюсь, она вам поможет.