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?


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

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;

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'
}

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

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"

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'
}

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.


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.


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

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

Konsolenausgabe: Heute ist MONTAG


1

Ich benutze Struktur wie unten:

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

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.


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

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 .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.