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

问题描述

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

例如,我有

var className = 'DocumentsList';

我可以做这样的事情

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

解决方法

Flutter(和Dart)没有执行此操作的功能。故意。他们实现了摇树,一种删除未使用代码的机制,以使您的应用更小,更快。但是,为此,编译器必须知道使用了什么代码,没有使用什么代码。如果您可以做您描述的事情,它就可能不知道使用了什么代码。

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

您想要的东西称为“反射”,您可以使用reflectablemirror之类的软件包添加一些功能,但是它们无法更改编译过程,它们也可以通过您事先指定的功能来工作。类需要反思。完全不可能动态使用(故意)。


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

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'),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")));
  }
}

这样,您的项目中就不会包含带有路由名称的字符串,在重命名时,这些字符串可以更改,错误键入或忘记。