繁体   English   中英

用 JSON 序列化/反序列化 Dart 的新枚举的最佳方法是什么?

[英]What is the best way to serialize/deserialize Dart's new enum with JSON?

我想利用 Dart 的新(实验性) enum功能而不是使用静态 const 字符串堆栈,但是使用 JSON 序列化/反序列化enum变量的最佳方法是什么? 我已经使它以这种方式工作,但肯定有更好的解决方案:

enum Status {
  none,
  running,
  stopped,
  paused
}

Status status1 = Status.stopped;
Status status2 = Status.none;

String json = JSON.encode(status1.index);
print(json);   // prints 2

int index = JSON.decode(json);
status2 = Status.values[index];
print(status2);  // prints Status.stopped

如果您使用索引进行序列化,您可能会被锁定为永远保持枚举的顺序相同,所以我更喜欢使用某种字符串形式。 有人想出这个吗?

作为先前建议的答案之一,如果您在客户端和服务器上共享相同的实现,那么序列化名称是我认为最好的方法,并且尊重SOLID 设计中的打开/关闭原则,说明:

“软件实体(类、模块、函数等)应该对扩展开放,对修改关闭”

如果您需要向 Enum 添加另一个成员,则使用索引而不是名称会弄乱代码的所有逻辑。 但是,使用该名称将允许扩展。

最重要的是,序列化枚举的名称,为了正确反序列化它,编写一个小函数,将枚举作为字符串给出,迭代枚举的所有成员并返回适当的成员。 如:

Status getStatusFromString(String statusAsString) {
  for (Status element in Status.values) {
     if (element.toString() == statusAsString) {
        return element;
     }
  }
  return null;
}

所以,要序列化:

Status status1 = Status.stopped;
String json = JSON.encode(status1.toString());
print(json) // prints {"Status.stopped"}

并反序列化:

String statusAsString = JSON.decode(json);
Status deserializedStatus = getStatusFromString(statusAsString);
print(deserializedStatus) // prints Status.stopped

这是迄今为止我发现的最好的方法。 希望这可以帮助 !

使用枚举的name属性和byName方法

下面是一个示例代码来展示如何使用它:

import 'dart:convert';

void main() {
  Person raj = Person(name: 'Raj', favIcecream: Icecream.pista);
  print(raj.toJson());

  Person rajV2 = Person.fromJson(raj.toJson());
  print(rajV2.toJson());

  final isBothInstanceEqual = raj == rajV2;
  print('> Both instancecs are equal is $isBothInstanceEqual');
}

enum Icecream {
  vanilla,
  pista,
  strawberry,
}

class Person {
  String name;
  Icecream favIcecream;
  Person({
    required this.name,
    required this.favIcecream,
  });

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'favIcecream': favIcecream.name, // <- this is how you should save
    };
  }

  factory Person.fromMap(Map<String, dynamic> map) {
    return Person(
      name: map['name'] ?? '',
      favIcecream: Icecream.values.byName(map['favIcecream']), // <- back to enum
    );
  }

  String toJson() => json.encode(toMap());

  factory Person.fromJson(String source) => Person.fromMap(json.decode(source));

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is Person &&
        other.name == name &&
        other.favIcecream == favIcecream;
  }

  @override
  int get hashCode => name.hashCode ^ favIcecream.hashCode;
}

如果您使用的是 Dart 2.15.0+ (Flutter 2.8.0+)

您可以使用添加到枚举的新name属性。

要将其转换为 json 值,您会这样做

Status status1 = Status.stopped;
String jsonValue = status1.name;
print(jsonValue); // prints "stopped"

要将其转换回枚举,您会这样做

String jsonValue = "stopped";
Status deserializedStatus = Status.values.byName(jsonValue);
print(deserializedStatus); // prints "Status.stopped"

我建议使用名为 json_serializable 的谷歌 aswome 库(此链接

如此处所述:使用 JsonValue 注释枚举值以指定要映射到目标枚举条目的编码值。 值可以是 String 或 int 类型。

enum StatusCode {
   @JsonValue(200)
   success,
   @JsonValue('500')
   weird,
  }

你可以在模型课上试试。

...
YourModel.fromJson(Map<String,dynamic> json){
    status = Status.values.elementAt(json['status']);
}

Map<String, dynamic> toJson(Status status){
   final Map<String, dynamic> data = <String, dynamic>{};
   data['status'] = status.index;
   return data;
}

...

看看我的回答here

在您的情况下,您可以将enum Color替换为您的enum Status

enum Status {
  none("nn"), // You can also use numbers as you wish
  running("rn"),
  stopped("st"),
  paused("pa");

  final dynamic jsonValue;
  const Status(this.jsonValue);
  static Status fromValue(jsonValue) =>
      Status.values.singleWhere((i) => jsonValue == i.jsonValue);
}

或者如果你想使用jsonize包,你可以这样做:

import 'package:jsonize/jsonize.dart';

enum Status with JsonizableEnum {
  none("nn"),
  running("rn"),
  stopped("st"),
  paused("pa");

  @override
  final dynamic jsonValue;
  const Status(this.jsonValue);
}

void main() {
  // Register your enum
  Jsonize.registerEnum(Status.values);

  Map<String, dynamic> myMap = {
    "my_num": 1,
    "my_str": "Hello!",
    "my_status": Status.running,
  };
  var jsonRep = Jsonize.toJson(myMap);
  var backToLife = Jsonize.fromJson(jsonRep);
  print(backToLife);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM