天天看点

Dart Metadata 使用Dart Metadata 使用

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);
}