Dart Wie man den "Wert" einer Aufzählung erhält

76

Bevor Enums in Dart verfügbar waren, habe ich einige umständliche und schwer zu wartende Codes geschrieben, um Enums zu simulieren, und möchte sie jetzt vereinfachen. Ich muss den Wert der Aufzählung als Zeichenfolge abrufen, wie dies mit Java möglich ist, aber nicht möglich ist.

Zum Beispiel gibt ein kleines Testcode-Snippet "day.MONDAY" zurück, wenn ich "MONDAY" möchte.

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

Stimmt es, dass ich die Zeichenfolge analysieren muss, um nur 'MONTAG' zu erhalten?

Nate Lockwood
quelle
Und es gibt keinen Iterator?
Nate Lockwood
1
Dart bietet eine Methode zum Abrufen des
Wertes descriptionEnum
Dart braucht so etwas wie eine eingebaute 'Name'-Eigenschaft, um all diese Dummheit einzudämmen (z. B. day.MONDAY.name).
Pete Alvin

Antworten:

50

Leider haben Sie Recht, dass die toString-Methode zurückgegeben "day.MONDAY"wird und nicht die nützlichere "MONDAY". Sie können den Rest der Zeichenfolge wie folgt abrufen:

day theDay = day.MONDAY;      
print(theDay.toString().substring(theDay.toString().indexOf('.') + 1));

Zugegeben, kaum bequem.

Wenn Sie alle Werte iterieren möchten, können Sie Folgendes tun day.values:

for (day theDay in day.values) {
  print(theDay);
}
lrn
quelle
1
Die alten Enums stackoverflow.com/questions/15854549 bieten mehr Flexibilität, können jedoch nicht als Konstanten verwendet werden. Wenn Sie eine Bibliothek erstellen und mit einem Präfix importieren, können Sie dies umgehen (siehe diese Antwort in der Frage über stackoverflow.com/a/15855913/217408 ).
Günter Zöchbauer
Was ist das Problem bei der Verwendung von "enum-class" -Instanzen als Konstanten?
lrn
Es sollte kein Problem geben, const-Instanzen einer Klasse zu erstellen und sie als statische const-Mitglieder verfügbar zu machen - das macht die Implementierung der Sprachaufzählung sowieso:class MyEnum { static const MyEnum someItem = const MyEnum(0); static const MyEnum someOtherItem = const MyEnum(1); final int id; const MyEnum(this.id); }
lrn
@Irm Ich konnte einige Methoden, die ich benötige, umschreiben und testen. Vielleicht wird die Aufzählung eines Tages erweitert, um den Namen als Zeichenfolge anzugeben.
Nate Lockwood
@lrn Ich habe es versucht und es hat funktioniert. Vielen Dank für den Hinweis. Das letzte Mal, als ich es versuchte, bekam ich einen Fehler bei doSomething1([Status status = Status.off]) { DartPad
Günter Zöchbauer
95

Etwas kürzer:

String day = theDay.toString().split('.').last;
Jannie Theunissen
quelle
8
Einfacherer Weg: theDay.toString (). split ('.'). last
Hani
1
Danke, @Hani! Ihre Verbesserung ist sowohl einfacher als auch "sicherer". Die Antwort wurde aktualisiert.
Jannie Theunissen
90

Dart 2.7 verfügt über eine neue Funktion namens Erweiterungsmethoden . Jetzt können Sie so einfach Ihre eigenen Methoden für Enum schreiben!

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'
}
mbartn
quelle
Wie hier beschrieben, konnte ich die Erweiterung aus einer anderen Datei nicht verwenden, obwohl die Aufzählung korrekt importiert wurde. Es hat funktioniert, als ich dem Beispiel eines Dokuments gefolgt bin und der Erweiterung einen Namen hinzugefügt habe: "Erweiterung Formatierung am Tag". Vielleicht haben Sie eine Bearbeitung, wenn es nicht nur ich ist. Auch die Antwort sollte mit einer Mischung aus Jannie- und Mbartn-Antworten aktualisiert werden.
ko0stik
1
Ich habe die letzten Bearbeitungsänderungen zurückgesetzt, da dies ohne den Namen der Erweiterung nicht funktioniert
Dies ist nicht die beste Lösung. Kalpesh Dabhi bietet hier eine bessere: stackoverflow.com/a/60615370/9695154
Gustavo Rodrigues
describeEnumist eine
reine Flatter-
48

Der einfachste Weg, den Namen einer Aufzählung zu erhalten, ist eine Standardmethode aus dem flattern / 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');
}
gbixahue
quelle
5
Dies kann nur in Flutter verwendet werden. Bei Nur-Dart-Code (mit Dart anstelle von Flattern ausführen) wird ein Fehler verursacht.
Roun
20

Es gibt eine elegantere Lösung:

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"
Daniel Vladco
quelle
12
Nennst du es elegant? Wie? Durch Hinzufügen von zusätzlichem Speicherplatz und 20 neuen Zeilen?
GensaGames
1
Dies ist eigentlich ein Anti-Muster. Wenn Sie Ihrer Aufzählung weitere Werte hinzufügen müssen, müssen Sie den Code an zwei Stellen ändern, da Sie auch die Karte ändern sollten. Stellen Sie sich vor, Sie haben Hunderte von Aufzählungen in einer großen App und Hunderte von Karten für sie in verschiedenen Teilen der App. ziemlich schwer zu pflegen.
Daniel Leiszen
3
Das gefällt mir wirklich sehr gut. Die anderen Lösungen scheinen hacky.
Tony
7

Dies ist Ihre Aufzählung:

enum Day {
  monday,
  tuesday,
}

Erstellen Sie eine Erweiterung (muss möglicherweise import 'package:flutter/foundation.dart';)

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

Verwendung:

void main() {
  Day monday = Day.monday;
  String inString = monday.inString; // 'monday'
}
CopsOnRoad
quelle
1
Ausnutzen describeEnumist der richtige Weg. Die Verwendung einer Erweiterung ist ein
guter
6

Ich benutze die folgenden Funktionen, um den Namen des Aufzählungswerts und umgekehrt den Aufzählungswert anhand des Namens zu erhalten:

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

Bei Verwendung von Dart 2.7 und neuer funktionieren hier Erweiterungsmethoden (sowie für alle anderen Objekte):

extension EnumX on Object {
  String asString() => toString().split('.').last;
}

Die obige Implementierung hängt nicht von den spezifischen Aufzählungen ab.

Anwendungsbeispiele:

enum Fruits {avocado, banana, orange}
...
final banana = enumValueFromString('banana', Fruits.values);
print(enumValueToString(banana)); // prints: "banana"
print(banana.asString()); // prints: "banana"

Bearbeiten vom 05.04.2020: Nullabilitätsprüfungen hinzugefügt. valuesParameter könnte Iterablenicht unbedingt sein List. Implementierung der Erweiterungsmethode hinzugefügt. Die <Fruits>Anmerkung wurde aus dem Beispiel entfernt, um zu zeigen, dass die Duplizierung des Klassennamens nicht erforderlich ist.

Alexandr Priezzhev
quelle
Danke, dass du Alexandr geteilt hast! Genau das habe ich in meinem Fall
gesucht ;-)
beste Antwort für Deal Enum
Mahmoud Abu Elheja
3

Ich bin so darüber hinweggekommen, dass ich ein Paket gemacht habe:

https://pub.dev/packages/enum_to_string

Hat auch eine praktische Funktion, die es nimmt enum.ValueOneund zu " Value one" analysiert

Es ist eine einfache kleine Bibliothek, aber ihre Einheit wurde getestet und ich freue mich über Ergänzungen für Randfälle.

Ryan Knell
quelle
2

Mein Ansatz ist nicht grundlegend anders, könnte aber in einigen Fällen etwas bequemer sein:

enum Day {
  monday,
  tuesday,
}

String dayToString(Day d) {
  return '$d'.split('.').last;
}

In Dart können Sie eine Aufzählung nicht anpassen toString Methode halte ich diese Problemumgehung für die Hilfsfunktion für erforderlich und für einen der besten Ansätze. Wenn Sie in diesem Fall korrekter sein möchten, können Sie den ersten Buchstaben der zurückgegebenen Zeichenfolge in Großbuchstaben schreiben.

Sie können auch eine dayFromStringFunktion hinzufügen

Day dayFromString(String s) {
  return Day.values.firstWhere((v) => dayToString(v) == s);
}

Anwendungsbeispiel:

void main() {
  Day today = Day.monday;
  print('Today is: ${dayToString(today)}');
  Day tomorrow = dayFromString("tuesday");
  print(tomorrow is Day);
}
Vince Varga
quelle
2
enum day {MONDAY, TUESDAY}
print( 'Today is ${describeEnum(day.MONDAY)}' );

Konsolenausgabe: Heute ist MONTAG

Tim
quelle
1

Ich benutze Struktur wie unten:

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

Ich hatte das gleiche Problem in einem meiner Projekte und die vorhandenen Lösungen waren nicht sehr sauber und es wurden keine erweiterten Funktionen wie JSON-Serialisierung / Deserialisierung unterstützt.

Flutter unterstützt derzeit nativ keine Aufzählung mit Werten. Ich habe es jedoch geschafft, ein Hilfspaket Vnummit Klassen- und Reflektorimplementierung zu entwickeln, um dieses Problem zu beheben.

Adresse an das Repository:

https://github.com/AmirKamali/Flutter_Vnum

Um Ihr Problem mit zu beantworten Vnum, können Sie Ihren Code wie folgt implementieren:

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

Sie können es verwenden wie:

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

Es gibt mehr Dokumentation im Github Repo, hoffe es hilft dir.

Amir.n3t
quelle
1
enum day {MONDAY, TUESDAY}
print(day.toString().split('.')[1]);
OR
print(day.toString().split('.').last);
Haroon Khan
quelle
1

Anstatt die Erweiterung für jede Aufzählung zu definieren, können wir die Erweiterung für das Objekt definieren und .enumValuevon jeder Aufzählung aus auf sie zugreifen .

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

Mit dieser Option können Sie sogar eine Mehrwortaufzählung definieren, bei der Wörter _in ihrem Namen durch (Unterstrich) getrennt sind .

Erluxman
quelle