Flutter

Dart:处理模型转换 `空字段` 引发的问题

2021-08-23  本文已影响0人  李小轰
引言

在 flutter 开发中,数据源与实体模型的转换是频繁的。将字符串转成 map ,将 map 转成 model 模型,成了家常便饭。转换的方式,我们大概会这么做:

{
    "code": 0,
    "data": [
        {"name": "rex"},
        {"age": 10}
    ]
}
///数据模型
class TestModel {
  final int code;
  final List<Student> data;
  TestModel(this.code, this.data);

  factory TestModel.fromMap(Map<String, dynamic> value) {
    return TestModel(
      value["code"] as int,
      (value["data"] as List).map((e) => Student.fromMap(e)).toList(),
    );
  }
}

class Student {
  final String name;
  final int age;
  Student(this.name, this.age);

  factory Student.fromMap(Map<String, dynamic> value) {
    return Student(
      value["name"] as String,
      value["age"] as int,
    );
  }
void main() {
  String jsonStr = """
  {
    "data": [
      {"name": "rex"},
      {"age": 10}
    ]
  }
  """;

  final Map<String, dynamic> map = new Map<String, dynamic>.from(json.decode(jsonStr));

  TestModel model2 = TestModel.fromMap(map);
  print(model2.code + 1);
}
分析错误

原来,我们与服务端约定好的数据结构里,服务端漏传了一个字段 code ,我们在 map 转模型实体的过程中使用 as 进行强制类型转换,将 null 当做数值类型来进行运算操作,此时发生报错。


处理方案:

我们希望在进行类型转换时,如果map中字段不存在,则赋值相应类型默认值。(默认值为 false0""等等非null类型)

/// 保证类型解析有默认值,不会出现null强转类型异常
class ParserWithNotNull {
  final Object source;
  Type _type;

  ParserWithNotNull(this.source) {
    _type = _asyncType;
  }

  Type get _asyncType {
    if (source == null) {
      return null;
    }
    if (source is num) {
      return num;
    }
    if (source is String) {
      return String;
    }
    if (source is List) {
      return List;
    }
    if (source is Map) {
      return Map;
    }
    if (source is bool) {
      return bool;
    }
    return null;
  }

  ///获取 bool 类型内容
  bool get boolValue {
    if (_type is bool) {
      return source as bool;
    } else {
      return false;
    }
  }

  ///获取 String 类型内容
  String get stringValue {
    switch (_type) {
      case num:
      case String:
      case bool:
      case List:
      case Map:
        return source.toString();
        break;
      default:
        return "";
        break;
    }
  }

  ///获取 int 类型内容
  int get intValue {
    switch (_type) {
      case num:
        return (source as num).toInt();
        break;
      case String:
        return int.parse(source.toString());
        break;
      case bool:
        return (source as bool) ? 1 : 0;
        break;
      default:
        return 0;
        break;
    }
  }

  ///获取 double 类型内容
  double get doubleValue {
    switch (_type) {
      case num:
        return (source as double).toDouble();
        break;
      case String:
        return double.parse(source.toString());
        break;
      default:
        return 0;
        break;
    }
  }

  ///获取 List 类型内容
  List<ParserWithNotNull> get arrayValue {
    if (_type == List) {
      return (source as List<dynamic>)
          .map((e) => ParserWithNotNull(e))
          .toList();
    } else {
      return List<ParserWithNotNull>();
    }
  }

  ///获取 map 类型内容
  Map<String, ParserWithNotNull> get mapValue {
    if (_type == Map) {
      return (source as Map<String, dynamic>)
          .map((key, value) => MapEntry(key, ParserWithNotNull(value)));
    } else {
      return Map<String, ParserWithNotNull>();
    }
  }

  ///提供根据 key/index 获取 map 与 list 对应 value 的快捷方法
  ParserWithNotNull operator [](Object target) {
    ParserWithNotNull result = ParserWithNotNull(null);
    if (target is int) {
      //从 list 中取值
      final list = arrayValue;
      if (target < list.length) {
        result = list[target];
      }
    } else {
      //从map中取值
      final map = mapValue;
      if (map.containsKey(target)) {
        result = mapValue[target];
      }
    }
    return result;
  }
}

使用方式:

class TestModel {
  ...省略...
  factory TestModel.fromJson(ParserWithNotNull value) {
    return TestModel(
      value["code"].intValue,
      value["data"].arrayValue.map((e) => Student.fromJson(e)).toList(),
    );
  }
}

class Student {
  ...省略...
  factory Student.fromJson(ParserWithNotNull value) {
    return Student(
      value["name"].stringValue,
      value["age"].intValue,
    );
  }
}

注意到我们方法的入参不再是 Map ,而是 ParserWithNotNull,通过ParserWithNotNull进行数据获取中转,当为 null 时,会直接赋值各类型的默认值,保证非null。

...省略
  final Map<String, dynamic> map = new Map<String, dynamic>.from(json.decode(jsonStr));
  final ParserWithNotNull parser = ParserWithNotNull(map);

  TestModel model = TestModel.fromJson(parser);
  print(model.code + 1);

运行,打印结果为:1 (code变量被赋值默认值 0)

上一篇下一篇

猜你喜欢

热点阅读