Dart提供了类似于Java注解一样的机制 metadata
,通过使用 metadata
可以实现与注解一样的功能,中文我们称它为元数据。我们来看一段官方的使用描述:
Metadata can appear before a library, class, typedef, type parameter, constructor, factory, function, field, parameter, or variable declaration and before an import or export directive.
这段话是说 Metadata
可以出现在库、类、typedef
,参数类型,构造函数,工厂构造函数,方法,字段,参数,或者变量和 import
以及 export
指令前面。可见 metadata 使用范围之广。
原文档在这里。
官方给了我们定义的例子:
Use metadata to give additional information about your code. A metadata annotation begins with the character @, followed by either a reference to a compile-time constant (such as deprecated) or a call to a constant constructor.
Two annotations are available to all Dart code: @deprecated
and @override
. For examples of using @override
, see Extending a class. Here’s an example of using the @deprecated
annotation:
class Television {
/// _Deprecated: Use [turnOn] instead._
@deprecated
void activate() {
turnOn();
}
/// Turns the TV's power on.
void turnOn() {...}
}
You can define your own metadata annotations. Here’s an example of defining a @todo
annotation that takes two arguments:
library todo;
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}
And here’s an example of using that @todo
annotation:
import 'todo.dart';
@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
Metadata can appear before a library, class, typedef, type parameter, constructor, factory, function, field, parameter, or variable declaration and before an import or export directive. You can retrieve metadata at runtime using reflection.
但是这里并没有说怎么使用 reflection
,下面我们来看看怎么使用反射获取 metadata 。
为了能够使用反射 dart
引入了 mirrors
系统,在 dart:mirrors
包下。这里我们主要讲跟类相关的,包括:
InstanceMirror
ClassMirror
DeclarationMirror
ParameterMirror
MethodMirror
TypeMirror
获取 mirror
的方法:
InstanceMirror reflect(Object)
ClassMirror reflectClass(Type)
TypeMirror reflectType(Type)
下面是一个获取 metadata 的 demo:
main(List<String> args) {
getWorkAnnotation();
}
void getWorkAnnotation() {
ClassMirror classMirror = reflectClass(TestMixin);
// 获取 class 上的元数据
classMirror.metadata.forEach((metadata) {
print(metadata.reflectee.who + ' ==> ' + metadata.reflectee.what);
});
// 获取 field 和 method 上的元数据
classMirror.declarations.forEach((Symbol key, DeclarationMirror value) {
if (value is MethodMirror) {
if (value.simpleName == #getRequest) {
value.metadata.forEach((metadata) {
if (metadata.reflectee is Todo) {
print(metadata.reflectee.who + ' ==> ' + metadata.reflectee.what);
} else if (metadata.reflectee is TestAnnotation) {
print(metadata.reflectee.id.toString() +
' ==> ' +
(metadata.reflectee.name == null
? 'null'
: metadata.reflectee.name));
} else if (metadata.reflectee is GET) {
print(metadata.reflectee.value);
}
});
// 获取方法中参数上的元数据
value.parameters.forEach((param) {
param.metadata.forEach((metadata) {
if (metadata.reflectee is Query) {
if (metadata.reflectee.value == null) {
print(
'args name ==> ' + MirrorSystem.getName(param.simpleName));
} else {
print(metadata.reflectee.value);
}
}
});
});
}
}
});
}
@Todo('wyndam', 'work')
abstract class TestMixin {
@GET(value: 'https://www.baidu.com/')
void getRequest(@Query(value: 'q') String param);
}
class GET {
final String value;
const GET({this.value});
}
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}