Dart 反射和镜像详解
简介
反射是在运行时检查、修改和调用程序元素的能力。Dart 通过 mirrors 包提供反射功能,可以用于运行时获取类型信息、调用方法等。
基本概念
镜像类型
dart
import 'dart:mirrors';
// 实例镜像
InstanceMirror instanceMirror = reflect(object);
// 类镜像
ClassMirror classMirror = reflectClass(String);
// 库镜像
LibraryMirror libraryMirror = currentMirrorSystem().findLibrary(Symbol('dart.core'));
符号
dart
// 创建符号
Symbol symbol = Symbol('methodName');
// 符号转字符串
String name = MirrorSystem.getName(symbol);
// 字符串转符号
Symbol symbol = Symbol('methodName');
类型反射
获取类型信息
dart
class Person {
String name;
int age;
Person(this.name, this.age);
void sayHello() {
print('Hello, I am $name');
}
}
void inspectClass() {
ClassMirror mirror = reflectClass(Person);
// 获取构造函数
mirror.declarations.forEach((Symbol name, DeclarationMirror declaration) {
if (declaration is MethodMirror && declaration.isConstructor) {
print('Constructor: ${MirrorSystem.getName(name)}');
}
});
// 获取属性
mirror.declarations.forEach((Symbol name, DeclarationMirror declaration) {
if (declaration is VariableMirror) {
print('Property: ${MirrorSystem.getName(name)}');
}
});
// 获取方法
mirror.declarations.forEach((Symbol name, DeclarationMirror declaration) {
if (declaration is MethodMirror && !declaration.isConstructor) {
print('Method: ${MirrorSystem.getName(name)}');
}
});
}
方法调用
调用实例方法
dart
void invokeMethod() {
var person = Person('John', 30);
InstanceMirror mirror = reflect(person);
// 调用方法
mirror.invoke(Symbol('sayHello'), []);
// 调用带参数的方法
mirror.invoke(Symbol('setAge'), [25]);
// 获取返回值
var result = mirror.invoke(Symbol('getAge'), []);
print('Age: ${result.reflectee}');
}
调用静态方法
dart
void invokeStaticMethod() {
ClassMirror mirror = reflectClass(Math);
// 调用静态方法
var result = mirror.invoke(Symbol('max'), [10, 20]);
print('Max: ${result.reflectee}');
}
属性访问
读写属性
dart
void accessProperties() {
var person = Person('John', 30);
InstanceMirror mirror = reflect(person);
// 读取属性
var name = mirror.getField(Symbol('name')).reflectee;
print('Name: $name');
// 设置属性
mirror.setField(Symbol('name'), 'Jane');
}
属性监听
dart
void watchProperties() {
var person = Person('John', 30);
InstanceMirror mirror = reflect(person);
// 监听属性变化
mirror.type.declarations.forEach((Symbol name, DeclarationMirror declaration) {
if (declaration is VariableMirror) {
var oldValue = mirror.getField(name).reflectee;
// 实现属性变化通知
}
});
}
完整示例
dart
import 'dart:mirrors';
class User {
String name;
int age;
bool _isAdmin;
User(this.name, this.age, [this._isAdmin = false]);
void greet() {
print('Hello, I am $name');
}
bool checkAccess(String resource) {
return _isAdmin;
}
@override
String toString() => 'User($name, $age)';
}
class ReflectionHelper {
static void inspectObject(Object object) {
InstanceMirror instanceMirror = reflect(object);
ClassMirror classMirror = instanceMirror.type;
print('Class: ${MirrorSystem.getName(classMirror.simpleName)}');
// 检查属性
print('\nProperties:');
classMirror.declarations.forEach((Symbol name, DeclarationMirror declaration) {
if (declaration is VariableMirror) {
var propertyName = MirrorSystem.getName(name);
var value = instanceMirror.getField(name).reflectee;
print(' $propertyName = $value');
}
});
// 检查方法
print('\nMethods:');
classMirror.declarations.forEach((Symbol name, DeclarationMirror declaration) {
if (declaration is MethodMirror && !declaration.isConstructor) {
var methodName = MirrorSystem.getName(name);
var parameters = declaration.parameters
.map((p) => MirrorSystem.getName(p.simpleName))
.join(', ');
print(' $methodName($parameters)');
}
});
}
static void invokeMethod(Object object, String methodName, List arguments) {
InstanceMirror instanceMirror = reflect(object);
instanceMirror.invoke(Symbol(methodName), arguments);
}
static void setProperty(Object object, String propertyName, dynamic value) {
InstanceMirror instanceMirror = reflect(object);
instanceMirror.setField(Symbol(propertyName), value);
}
static dynamic getProperty(Object object, String propertyName) {
InstanceMirror instanceMirror = reflect(object);
return instanceMirror.getField(Symbol(propertyName)).reflectee;
}
}
void main() {
var user = User('John', 30, true);
// 检查对象
ReflectionHelper.inspectObject(user);
// 调用方法
ReflectionHelper.invokeMethod(user, 'greet', []);
// 修改属性
ReflectionHelper.setProperty(user, 'name', 'Jane');
// 读取属性
var age = ReflectionHelper.getProperty(user, 'age');
print('Age: $age');
}
最佳实践
- 谨慎使用反射
- 注意性能影响
- 处理好异常情况
- 提供替代方案
- 合理使用缓存
注意事项
- 反射在生产环境可能受限
- 影响代码大小和性能
- 可能破坏类型安全
- 不是所有平台都支持
- 注意版本兼容性
总结
反射和镜像提供了强大的运行时编程能力,但应该谨慎使用。在开发工具、测试框架等场景下比较适合使用反射,而在生产应用中应该尽量避免使用。