Dart中如何通过字符串形式的变量引用路径获取对应变量值
Dart 按字符串路径访问对象属性方案
你不需要逐一手写所有类的toJson()方法,以下是按改造成本从低到高排序的可落地方案:
方案1:基于dart:mirrors的原生反射实现(零改造成本,仅支持纯Dart环境)
如果你的项目是Dart命令行工具、服务端应用,没有Flutter跨端编译限制,可以直接用Dart内置的镜像反射能力实现路径访问,完全不需要修改任何现有业务类代码。
工具函数实现:
import 'dart:mirrors'; /// 按路径从根对象上获取属性值,路径段用.分隔 dynamic getValueByPath(dynamic root, String propertyPath) { final pathSegments = propertyPath.split('.'); dynamic currentValue = root; for (final segment in pathSegments) { if (currentValue == null) return null; final instanceMirror = reflect(currentValue); currentValue = instanceMirror.getField(Symbol(segment)).reflectee; } return currentValue; }
使用示例:
class A { B b = B(); } class B { String c = "apple"; } void main() { A a = A(); // 注意路径不需要带根实例名a,因为我们直接传入a作为根对象 final ref = "b.c"; print(getValueByPath(a, ref)); // 输出apple }
注意:Flutter 移动端/桌面端/Web端编译时禁用了dart:mirrors,这类跨端场景不能使用本方案
方案2:代码生成自动序列化+路径遍历(兼容所有Flutter/Dart场景,改造成本极低)
手写toJson()成本高的问题完全可以通过代码生成解决,不需要你手动写任何嵌套序列化逻辑:
- 引入依赖:生产环境依赖
json_annotation,开发环境依赖build_runner和json_serializable - 给所有需要支持动态路径访问的类加固定注解和模板方法,不需要写具体序列化逻辑:
import 'package:json_annotation/json_annotation.dart'; // 指向生成的代码文件,文件名和你当前的dart文件名一致即可 part 'demo.g.dart'; @JsonSerializable(explicitToJson: true) class A { B b = B(); // 以下两行是固定模板,所有类写法完全一致 factory A.fromJson(Map<String, dynamic> json) => _$AFromJson(json); Map<String, dynamic> toJson() => _$AToJson(this); } @JsonSerializable(explicitToJson: true) class B { String c = "apple"; factory B.fromJson(Map<String, dynamic> json) => _$BFromJson(json); Map<String, dynamic> toJson() => _$BToJson(this); } - 执行命令
dart run build_runner build,所有类的嵌套toJson()/fromJson()逻辑会自动生成,后续类字段修改后只需要重跑该命令即可更新逻辑 - 实现通用路径访问工具:
dynamic getValueByPath(dynamic rootObj, String propertyPath) { // 自动调用生成的toJson转成嵌套Map,无需手写转换逻辑 final Map<String, dynamic> rootMap = rootObj.toJson(); final pathSegments = propertyPath.split('.'); dynamic current = rootMap; for (final seg in pathSegments) { // 支持数组索引访问,比如路径b.itemList.0.name final index = int.tryParse(seg); if (index != null && current is List) { current = current[index]; continue; } if (current is! Map || !current.containsKey(seg)) return null; current = current[seg]; } return current; }
本方案优势:
- 全平台兼容,没有Flutter反射限制
- 性能好,所有逻辑在编译期生成,没有运行时反射开销
- 改造成本极低,只需要给类加注解和两行固定模板,不需要手写任何嵌套转换逻辑,是Flutter生态的主流实现方式
方案3:代码生成式反射(适合复杂动态场景)
如果你需要的不只是属性读取,还要支持动态修改属性、调用方法等更灵活的反射能力,可以使用reflectable包。它的原理是在编译期只生成你标记过的类的反射元数据,不会带来全量反射的包体积问题,全平台兼容。
使用时只需要给需要支持反射的类加自定义注解,跑build命令生成反射代码后,就可以写出和dart:mirrors体验几乎一致的路径访问逻辑,不需要实现toJson方法,灵活度比序列化方案更高,适合动态规则、动态表单这类复杂场景。
选型建议
- 纯Dart服务端/脚本场景优先选方案1,零改造成本
- Flutter应用仅需要按路径读属性优先选方案2,生态最成熟、坑最少
- 需要复杂动态反射能力选方案3
内容的提问来源于stack exchange,提问作者Afinas EM
相关产品推荐
相关产品推荐

