Flutter反射机制插件built_mirrors的使用

Flutter反射机制插件built_mirrors的使用

built_mirrors 是一个用于生成 ClassMirror 的库,它可以从带有 @reflectable@Reflectable() 注解的类中生成反射信息。通过这个库,你可以在运行时动态地获取类的结构、构造函数、方法和字段等信息。

1. 创建一个新的Dart项目

首先,创建一个新的Dart项目(可以是Flutter项目)。你可以使用以下命令来创建一个新项目:

flutter create my_project

2. 添加依赖

pubspec.yaml 文件中添加 built_mirrorsbuilt_runner 依赖。确保使用最新的版本号。

dependencies:
  built_mirrors: any

dev_dependencies:
  built_runner: any

3. 创建模型文件

lib 文件夹中创建一个名为 models.dart 的文件,并将以下代码粘贴到该文件中。这个文件定义了一些带有注解的类,这些类将被 built_mirrors 生成反射信息。

library built_mirrors.example.models;

import 'package:built_mirrors/built_mirrors.dart';

part 'models.g.dart';

class MyAnnotation extends Annotation {
  final String val1;
  final val2;
  const MyAnnotation(this.val1, {this.val2});
}

const myOtherAnnotation = _MyOtherAnnotation();
class _MyOtherAnnotation extends Annotation {
  const _MyOtherAnnotation();
}

@reflectable
class Person {
  Person({this.id, this.name, this.myDynamic, this.cars});
  int? id;
  @MyAnnotation('hello\uabcd', val2: null)
  String? name;
  var myDynamic;
  List<Car>? cars;

  String get myGetter => 'myGetter result';
  set mySetter(String val) => 'setting $val';
}

@reflectable
@myOtherAnnotation
class Car {
  int? id;
  @MyAnnotation(r'\uabcd', val2: null)
  String? engine;
  Car([this.id, this.engine]);
}

@reflectable
class EmptyClass {}

@reflectable
class ExtendedPerson extends Person {
  var extendedName;
  var otherExtended;
}

@reflectable
class ClassWithMethod {
  @myOtherAnnotation
  someMethod(@myOtherAnnotation String someParameter) {
    return 'someMethod';
  }

  @myOtherAnnotation
  someMethodWithNamedParams({@myOtherAnnotation String? someParameter}) {
    return 'someMethod';
  }
}

4. 编辑主文件

lib 文件夹中创建或编辑 main.dart 文件,并将以下代码粘贴到该文件中。这个文件展示了如何使用 built_mirrors 来反射类和方法。

library built_mirrors.example.main;

import 'models.dart';
import 'package:built_mirrors/built_mirrors.dart';

part 'main.g.dart';

@reflectable
@AnnotationWithFunction(otherFunction)
String someFunction(@myOtherAnnotation int p1, int p0, int p2) {
  return '';
}

void otherFunction() {}

class AnnotationWithFunction extends Annotation {
  const AnnotationWithFunction(this.function);

  final Function function;
}

void main() {
  // 初始化反射映射
  _initMirrors();

  // 获取 Person 类的 ClassMirror
  var personClassMirror = reflectType(Person);
  
  // 使用构造函数参数创建一个新的 Person 实例
  var p1 = personClassMirror?.constructors?['']?.call([], {'id': 1, 'name': 'person 1'});
  
  // 获取 Person 类的所有字段
  var p1Fields = personClassMirror?.fields;

  // 打印字段类型
  print("p1Fields['myDynamic'].type: ${p1Fields?['myDynamic']?.type}\n");
  print("p1Fields['cars'].type: ${p1Fields?['cars']?.type}\n");

  // 获取 Car 类的 ClassMirror 并创建一个新的 Car 实例
  Car car1 = reflectType(Car)?.constructors?['']?.call([1, 'v8']);
  print('car1:\n\tid: ${car1.id}\n\tengine: ${car1.engine}\n');

  // 将 car1 添加到 p1.cars
  p1.cars = [car1];

  print('\n--------------------------');
  print('reflecting "ClassWithMethod"');
  print('--------------------------');
  var methods = reflectType(ClassWithMethod)?.methods;
  print(methods?.keys); // 打印方法名
  print(methods?['someMethod']?.returnType); // 打印返回类型
  print(methods?['someMethod']?.annotations); // 打印注解
  print(methods?['someMethod']?.positionalParameters); // 打印位置参数
  print(methods?['someMethod']?.positionalParameters?[0].annotations); // 打印第一个位置参数的注解
  print(methods?['someMethod']?.positionalParameters?[0].type); // 打印第一个位置参数的类型

  print('\n--------------------------');
  print('reflecting "someFunction"');
  print('--------------------------');
  var sfMirror = reflectFunction(someFunction);
  print(sfMirror?.name); // 打印函数名
  print(sfMirror?.returnType); // 打印返回类型
  print(sfMirror?.annotations); // 打印注解
  print(sfMirror?.positionalParameters); // 打印位置参数
  print(sfMirror?.positionalParameters?[0].annotations); // 打印第一个位置参数的注解
  print(sfMirror?.positionalParameters?[0].type); // 打印第一个位置参数的类型
  print(sfMirror?.positionalParameters?[0].name); // 打印第一个位置参数的名称
  print(sfMirror?.positionalParameters?[1].name); // 打印第二个位置参数的名称
  print(sfMirror?.positionalParameters?[2].name); // 打印第三个位置参数的名称
}

5. 生成反射代码

在项目根目录下运行以下命令,生成反射代码。这将会生成 lib/models.g.dartlib/main.g.dart 文件,包含自动生成的反射信息。

dart run build_runner build

6. 运行项目

最后,运行 main.dart 文件,如果一切正常,你将在控制台看到以下输出:

p1Fields['myDynamic'].type: dynamic
p1Fields['cars'].type: [List, Car]

car1:
        id: 1
        engine: v8

--------------------------
reflecting "ClassWithMethod"
--------------------------
(someMethod, someMethodWithNamedParams)
dynamic
[Instance of '_MyOtherAnnotation']
[DeclarationMirror on someParameter]
[Instance of '_MyOtherAnnotation']
String

--------------------------
reflecting "someFunction"
--------------------------
someFunction
String
[Instance of 'AnnotationWithFunction']
[DeclarationMirror on p1, DeclarationMirror on p0, DeclarationMirror on p2]
[Instance of '_MyOtherAnnotation']
int
p1
p0
p2

更多关于Flutter反射机制插件built_mirrors的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter反射机制插件built_mirrors的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,作为IT专家,以下是如何在Flutter项目中使用built_mirrors插件来实现反射机制的一个简要说明和代码示例。built_mirrors是一个Dart库,用于在编译时生成代码以模拟反射机制,这在Flutter中尤其有用,因为Dart在运行时并不支持完整的反射。

步骤 1: 添加依赖

首先,你需要在pubspec.yaml文件中添加built_mirrors的依赖。请注意,built_mirrors实际上不是一个直接用于Flutter的插件,而是Dart的一个构建工具库。你可能需要配合built_value或类似的库来使用它。不过,为了说明,这里我们假设你有一个需要反射机制的场景。

dependencies:
  flutter:
    sdk: flutter
  built_value: ^8.0.0  # 确保版本与你的项目兼容
  built_collection: ^5.0.0

dev_dependencies:
  build_runner: ^2.0.0  # 用于运行构建脚本
  built_mirrors_generator: ^1.0.0  # 假设有这样的一个库来生成反射代码(注意:这不是真实存在的库,仅为示例)

注意built_mirrors_generator是一个假设的库,用于说明目的。实际上,你可能需要找到或创建一个类似的库来满足你的需求,或者手动实现反射逻辑。

步骤 2: 定义数据模型

使用built_value来定义你的数据模型,这将允许你在编译时生成不可变且类型安全的类。

// models/person.dart
import 'package:built_value/built_value.dart';
import 'package:built_collection/built_collection.dart';

abstract class Person implements Built<Person, PersonBuilder> {
  String get name;
  int get age;

  Person._();

  factory Person([updates(PersonBuilder b)]) = _$Person;

  static void _initializeBuilder(PersonBuilder b) {
    b
      ..name = 'John Doe'
      ..age = 30;
  }
}

步骤 3: 配置构建脚本

build.yaml文件中配置你的构建脚本,以生成所需的反射代码(假设有这样的配置)。

targets:
  $default:
    builders:
      built_mirrors_generator:
        enabled: true
        generate_for:
          - models/*.dart

注意:这同样是一个假设的配置,因为built_mirrors_generator并不是真实存在的构建器。你需要根据你的实际需求和可用的库来调整这部分配置。

步骤 4: 使用反射(假设方式)

由于Dart在运行时没有完整的反射支持,你可能需要通过编译时生成的代码来模拟这一行为。以下是一个假设的示例,说明如何使用生成的代码来实现类似反射的功能。

// main.dart
import 'package:flutter/material.dart';
import 'package:your_app/models/person.dart';
import 'reflect_generated_code.dart'; // 假设这是生成的反射代码

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Reflection Example'),
        ),
        body: Center(
          child: Text(reflectPerson(Person())),
        ),
      ),
    );
  }

  String reflectPerson(Person person) {
    // 假设generated_code.dart中有这样的函数
    return personReflector.describe(person);
  }
}

注意reflectPerson函数和personReflector是假设的,用于说明如何可能使用生成的反射代码。在实际项目中,你需要根据生成的代码来调整这部分逻辑。

结论

由于Dart在运行时没有完整的反射支持,使用类似built_mirrors的库(尽管它是一个假设的库)来模拟反射通常涉及在编译时生成代码。这通常意味着你需要配置构建脚本,定义数据模型,并可能编写一些自定义的生成器来生成所需的反射代码。

在实际项目中,你可能需要寻找或创建专门的库来满足你的反射需求,或者考虑使用其他设计模式来避免在Flutter/Dart中使用反射。

回到顶部