元数据

本章节将讨论Dart的元数据注解及其自定义,以及使用 mirors 包获取元数据等信息。

注解

元数据(metadata)用于给代码添加额外的信息,元数据注解(annotation,以下简称注解)以 @ 字符开头,后接一个常量值。我们在之前的代码中已多次见过 @override,它表示实例成员的重写,通常是一个类重写/实现了某个方法。

// ex412.dart
base class Vehicle { // 1
  void moveForward(int meters) {
    // ...
  }
}

base class Car implements Vehicle { // 2
  @override
  void moveForward(int meters) {
    // ...
  }
}

以下4个注解对所有的Dart代码可用:

  • @override
  • @Deprecated
  • @deprecated
  • @pragma

@Deprecated 标记某个功能已过时。

// ex481.dart
class Motorcycle {
  /// Use [start] instead
  @Deprecated('Use start instead')
  void ignite() {
    start();
  }

  /// Start the engine
  void start() {
    // ...
  }
}

@deprecated (注意首字母d小写),不携带附加的信息(message);事实上从源码中可以看出,它的message 被硬编码为"next release"

// dart-sdk/lib/core/annotations.dart
const Deprecated deprecated = Deprecated("next release");

@pragma 用于与Dart程序协同工作的工具。

自定义注解

可以像下面这样自定义注解。

// ex482.dart
class Table { // 1
  final String name;
  final String pk;

  const Table(this.name, {required this.pk}); // 2
}

@Table('tb_staff', pk: 'id') // 3
class Staff {
  int id;
  String name;
  List<String> skills;

  Staff(this.id, {required this.name, this.skills = const []});
}
  1. 这是一个普通的类 Table,其实例变量 name 表示表名,pk表示主键 ;
  2. Table提供了一个常量构造器,对于注解这是必须的;
  3. 使用注解 @TableStaff 类进行标记。

使用 mirrors

mirrors 包是Dart中的反射工具,类似Java中的java.lang.reflect。mirrors中的3个反射函数:

// dart-sdk/lib/mirrors/mirrors.dart
external InstanceMirror reflect(dynamic reflectee);
external ClassMirror reflectClass(Type key);
external TypeMirror reflectType(Type key, [List<Type>? typeArguments]);

reflect 反射一个实例,reflectClass 反射一个类,reflectType 反射一个类型。到底什么是反射(reflection)?下面通过一个示例来说明。

// ex483.dart
import 'dart:mirrors';

class _Foo {
  const _Foo();
}

class _Bar {
  const _Bar();
}

const foo = _Foo();
const bar = _Bar();

@foo
@bar
class Exam {
  @foo
  String? str;

  @bar
  void exam() {}
}

void main() {
  var examMirror = reflectClass(Exam); // 1
  for (var meta in examMirror.metadata) { // 2
    print(meta.reflectee);
  }
  // Output:
  // Instance of 'Foo'
  // Instance of 'Bar'

  for (var mem in examMirror.instanceMembers.entries) {
    print(mem); // 3
    print('  metadata: ${mem.value.metadata}'); // 4
  }

  // Output:
  // MapEntry(Symbol("=="): MethodMirror on '==')
  //   metadata: [InstanceMirror on Instance of '_Patch', InstanceMirror on Instance of 'pragma', InstanceMirror on Instance of 'pragma', InstanceMirror on Instance of 'pragma', InstanceMirror on Instance of 'pragma']
  // MapEntry(Symbol("hashCode"): MethodMirror on 'hashCode')
  //   metadata: [InstanceMirror on Instance of '_Patch']
  // MapEntry(Symbol("toString"): MethodMirror on 'toString')
  //   metadata: [InstanceMirror on Instance of '_Patch', InstanceMirror on Instance of 'pragma']
  // MapEntry(Symbol("noSuchMethod"): MethodMirror on 'noSuchMethod')
  //   metadata: [InstanceMirror on Instance of 'pragma', InstanceMirror on Instance of 'pragma', InstanceMirror on Instance of '_Patch', InstanceMirror on Instance of 'pragma']
  // MapEntry(Symbol("runtimeType"): MethodMirror on 'runtimeType')
  //   metadata: [InstanceMirror on Instance of '_Patch', InstanceMirror on Instance of 'pragma', InstanceMirror on Instance of 'pragma']
  // MapEntry(Symbol("str"): Instance of '_SyntheticAccessor')
  //   metadata: []
  // MapEntry(Symbol("str="): Instance of '_SyntheticAccessor')
  //   metadata: []
  // MapEntry(Symbol("exam"): MethodMirror on 'exam')
  //   metadata: [InstanceMirror on Instance of '_Bar']
}
  1. 反射Exam类;
  2. Exam类的元数据;
  3. 获取Exam类的实例成员;
  4. 获取Exam类的实例成员的元数据。

参考资料