Dart 代码生成详解
简介
代码生成是一种自动创建重复性代码的技术。在 Dart 中,我们可以使用 build_runner 和 source_gen 等工具来实现代码生成。
基本配置
pubspec.yaml 配置
yaml
dependencies:
json_annotation: ^4.8.1
dev_dependencies:
build_runner: ^2.4.6
json_serializable: ^6.7.1
source_gen: ^1.4.0
运行命令
bash
# 一次性生成
dart run build_runner build
# 持续监听并生成
dart run build_runner watch
JSON 序列化
基本用法
dart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
final String name;
final int age;
@JsonKey(name: 'is_student')
final bool isStudent;
User(this.name, this.age, this.isStudent);
// 从 JSON 转换
factory User.fromJson(Map<String, dynamic> json) =>
_$UserFromJson(json);
// 转换为 JSON
Map<String, dynamic> toJson() => _$UserToJson(this);
}
自定义转换
dart
@JsonSerializable()
class DateTime {
@JsonKey(
fromJson: _dateTimeFromEpoch,
toJson: _dateTimeToEpoch,
)
final DateTime timestamp;
static DateTime _dateTimeFromEpoch(int epoch) =>
DateTime.fromMillisecondsSinceEpoch(epoch);
static int _dateTimeToEpoch(DateTime time) =>
time.millisecondsSinceEpoch;
}
自定义生成器
Builder 定义
dart
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
Builder customBuilder(BuilderOptions options) =>
SharedPartBuilder([CustomGenerator()], 'custom');
class CustomGenerator extends Generator {
@override
String generate(LibraryReader library, BuildStep buildStep) {
// 生成代码的逻辑
final buffer = StringBuffer();
// 遍历所有类
for (var element in library.allElements) {
if (element is ClassElement) {
// 生成相关代码
buffer.writeln('// Generated code for ${element.name}');
}
}
return buffer.toString();
}
}
build.yaml 配置
yaml
targets:
$default:
builders:
custom_builder:
enabled: true
generate_for:
- lib/**/*.dart
完整示例
dart
// entity.dart
import 'package:json_annotation/json_annotation.dart';
part 'entity.g.dart';
@JsonSerializable()
class Product {
final String id;
final String name;
final double price;
@JsonKey(name: 'created_at')
final DateTime createdAt;
@JsonKey(defaultValue: false)
final bool isAvailable;
const Product({
required this.id,
required this.name,
required this.price,
required this.createdAt,
required this.isAvailable,
});
factory Product.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductToJson(this);
}
// custom_builder.dart
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
class RepositoryGenerator extends Generator {
@override
String generate(LibraryReader library, BuildStep buildStep) {
final buffer = StringBuffer();
for (var element in library.allElements) {
if (element is ClassElement) {
// 生成 Repository 类
buffer.writeln('''
class ${element.name}Repository {
final List<${element.name}> _items = [];
void add(${element.name} item) {
_items.add(item);
}
void remove(${element.name} item) {
_items.remove(item);
}
List<${element.name}> getAll() {
return List.unmodifiable(_items);
}
${element.name}? findById(String id) {
return _items.firstWhere(
(item) => item.id == id,
orElse: () => null,
);
}
}
''');
}
}
return buffer.toString();
}
}
// 使用示例
void main() {
final product = Product(
id: '1',
name: 'Example Product',
price: 99.99,
createdAt: DateTime.now(),
isAvailable: true,
);
// 序列化
final json = product.toJson();
print('JSON: $json');
// 反序列化
final restored = Product.fromJson(json);
print('Restored: $restored');
// 使用生成的 Repository
final repository = ProductRepository();
repository.add(product);
final found = repository.findById('1');
print('Found product: $found');
}
最佳实践
- 合理组织生成代码
- 使用适当的注解
- 处理好异常情况
- 提供清晰的文档
- 注意性能影响
注意事项
- 生成的代码不要手动修改
- 注意代码生成的时机
- 处理好依赖关系
- 合理使用配置选项
- 注意版本兼容性
总结
代码生成是一种强大的工具,可以帮助我们减少重复性工作,提高开发效率。通过合理使用代码生成工具,可以让代码更加规范和易于维护。