Dart Metadata 使用
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 使用范围之广。
Guide
原文档在这里。
官方给了我们定义的例子:
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 。
Mirrors
为了能够使用反射
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);
}