Dart Metadata 使用

范豪
2023-12-01

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);
}
 类似资料: