我有一个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重写此函数,有没有办法在Enum类型作为参数的情况下编写相同的函数?我试着但是我发现我无法施展给Enum。
//is something with the following signiture actually possible?
dynamic enumFromString(Type enumType,String value){
}
答案 0 :(得分:36)
镜子并不总是可用,但幸运的是你不需要它们。这是相当紧凑的,应该做你想要的。
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);
答案 1 :(得分:8)
使用镜像可以强制某些行为。我有两个想法。不幸的是,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 :(得分:7)
这是@mbartn使用扩展名的一种替代方法,它扩展了enum
本身而不是String
。
更快,但更乏味
// 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
}
较少泰迪斯,但速度较慢
如果O(n)的表现可以接受,您还可以结合@Collin Jackson的答案:
// 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
}
答案 3 :(得分:5)
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);
}
答案 4 :(得分:3)
您的枚举
enum Day {
monday,
tuesday,
}
添加此扩展名(需要import 'package:flutter/foundation.dart';
)
extension EnumEx on String {
Day toEnum() => Day.values.firstWhere((d) => describeEnum(d) == toLowerCase());
}
用法:
void main() {
String s = 'monday'; // String
Day monday = s.toEnum(); // Converted to enum
}
答案 5 :(得分:1)
我使用Dart 2.7 Collin Jackson's改进了Extension Methods答案,使其更加美观。
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
}
答案 6 :(得分:1)
将@CopsOnRoad 的解决方案概括为适用于任何枚举类型,
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);
答案 7 :(得分:1)
我的解决方案与Rob C的解决方案相同,但没有字符串插值:
T getEnumFromString<T>(Iterable<T> values, String value) {
return values.firstWhere((type) => type.toString().split(".").last == value,
orElse: () => null);
}
答案 8 :(得分:1)
我从JSON构建对象时遇到了同样的问题。在JSON中,值是字符串,但我想枚举以验证值是否正确。我写了这个可与任何枚举(不是指定的枚举)一起使用的助手:
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。我在这里没有故意使用类型。 枚举不在Dart中输入,将其视为使事情变得复杂。类仅用于缓存目的。
答案 9 :(得分:1)
有几个enums包允许我只获取枚举字符串而不是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
}
答案 10 :(得分:0)
我认为我的方法略有不同,但在某些情况下可能更方便。最后,我们有枚举类型的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中阻止了镜像,因为这会导致生成的程序包很大。
答案 11 :(得分:0)
我在一个项目中遇到了同样的问题,现有的解决方案不是很干净,并且不支持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仓库中还有更多文档,希望对您有所帮助。
答案 12 :(得分:0)
这是如此复杂,我做了一个简单的库就可以完成工作:
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
}
答案 13 :(得分:0)
这是将给定字符串转换为枚举类型的函数:
EnumType enumTypeFromString(String typeString) => EnumType.values
.firstWhere((type) => type.toString() == "EnumType." + typeString);
这是将给定枚举类型转换为字符串的方法:
String enumTypeToString(EnumType type) => type.toString().split(".")[1];
答案 14 :(得分:0)
@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);
}
也许有人会觉得这很有用...
答案 15 :(得分:0)
枚举有太多限制。扩展方法可以将方法添加到实例,但不能将静态方法添加到实例。
我真的很想能够做类似MyType.parse(myString)的事情,因此最终决定使用手动定义的类而不是枚举。通过一些布线,它在功能上几乎等同于枚举,但可以更轻松地对其进行修改。
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');
答案 16 :(得分:0)
另一种变体,可能如何解决:
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);
}
答案 17 :(得分:0)
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,
);
}
答案 18 :(得分:0)
我使用此功能,我认为它很简单,不需要任何“ hack”:
composer.lock
您可以像这样使用它:
combiner
答案 19 :(得分:0)
当迁移到空安全时,Iterable.firstWhere 方法不再接受 orElse: () => null。这是考虑到空安全的实现:
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!));
答案 20 :(得分:0)
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
答案 21 :(得分:0)
简化版:
import 'package:flutter/foundation.dart';
static Fruit? valueOf(String value) {
return Fruit.values.where((e) => describeEnum(e) == value).first;
}
使用方法 describeEnum
可以帮助您避免使用拆分来获取元素的名称。