根据类型名称动态创建实例



问题是,如果我有包含其名称的字符串变量,我可以创建类实例吗?

例如,我有

var className = 'DocumentsList';

我能做一些像这个的东西吗

var docListWidget = createInstance(className[, params]);

Flutter(和Dart(没有这样做的设施。故意地它们实现了树抖动,这是一种删除未使用代码的机制,可以让你的应用程序变得更小更快。然而,要做到这一点,编译器必须知道使用了什么代码,不使用什么代码。如果你能做你描述的事情,它就不可能知道会使用什么代码。

所以不,这是不可能的。没有那么大的自由度。如果你事先知道它将是哪个字符串,你可以使用一个大的switch语句来创建基于字符串的类。这是静态的,编译器可以使用它。

你想要的被称为";反射;您可以使用包(如reflectable或mirror(添加一些功能,但它们不能改变编译过程,它们也可以通过预先指定哪些类需要反射来工作。完全动态的使用是不可能的(故意的(。


由于您提到了路由表:您不能从字符串创建类,但是您可以从类创建字符串:

import 'package:flutter/material.dart';
typedef Builder<T> = T Function(BuildContext context);
String routeName<T extends Widget>() {
return T.toString().toLowerCase();
}
MapEntry<String, Builder<Widget>> createRouteWithName<T extends Widget>(Builder<T> builder) {
return new MapEntry(routeName<T>(), (context) => builder(context));
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: routeName<ScreenPicker>(),
routes: Map.fromEntries([
createRouteWithName((context) => ScreenPicker()),
createRouteWithName((context) => ScreenOne()),
createRouteWithName((context) => ScreenTwo()),
]),
);
}
}
class ScreenPicker extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("Navigate a route")), 
body: Column(children: [
RaisedButton(
child: Text('One'),
onPressed: () => Navigator.pushNamed(context, routeName<ScreenOne>())),
RaisedButton(
child: Text('Two'),
onPressed: () => Navigator.pushNamed(context, routeName<ScreenTwo>())),
]));
}
}
class ScreenTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("Second Screen")), body: Center(child: Text("Two")));
}
}
class ScreenOne extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text("First Screen")), body: Center(child: Text("One")));
}
}

这样,您的项目中就没有可能在重命名某些内容时更改、键入错误或忘记的带有路由名称的字符串。

最好的方法是使用命名构造函数,如:

class MyClass {
const MyClass.create();
}

因此,执行此操作的方法是传递调用中方法的Type。记住,你可以在不调用它的情况下传递函数,比如:

Get.lazyPut(MyClass.create);

如果你真的需要使用String来识别类类型,我建议你为它创建一些映射

rootBundle中有一些函数在这种情况下很有用,比如rootBundle.loadString((,它可以用来从文件中加载代码。

希望这有帮助。

最新更新