如何在Dart中动态执行(如Eval)?

时间:2012-11-27 13:16:54

标签: dynamic eval dart

自从开始使用Dart以来,我一直在寻找一种方法来执行Dart(Text)Source(同一程序可能会动态生成)作为Code。就像臭名昭着的“eval()”函数一样。

最近我发现了一些暗示,Isolates之间的通信端口支持某种“Spawn”,似乎它可能允许这种“技巧”。在Ruby中,还可以动态加载模块作为语言功能,也许在Dart中有一些方法可以做到这一点?

任何线索或简单的例子将不胜感激。

提前致谢!

3 个答案:

答案 0 :(得分:9)

Ladislav Thon提供了这个答案(在Dart论坛上),

我相信说Dart永远不会有eval是非常安全的。但它将有其他更结构化的动态生成代码的方法(代码名称镜像构建器)。但是现在没有类似的东西了。

有两种产生隔离的方法:spawnFunction,它从新隔离区中的现有代码运行现有函数,所以没有你想要的东西,以及spawnUri,它从给定的URI下载代码并在新的隔离区中运行它。这本质上是动态代码加载 - 但动态加载的代码与现有代码隔离。它运行在一个新的隔离区中,因此与它通信的唯一方法是通过消息传递(通过端口)。

谢谢Ladislav ......

答案 1 :(得分:3)

您可以通过首先从字符串构造数据URI,然后将其传递到Isolate.spawnUri中来将字符串作为Dart代码运行。

import 'dart:isolate';

void main() async {
  final uri = Uri.dataFromString(
    '''
    void main() {
      print("Hellooooooo from the other side!");
    }
    ''',
    mimeType: 'application/dart',
  );
  await Isolate.spawnUri(uri, [], null);
}

请注意,您只能在JIT模式下执行此操作,这意味着,您可能会从中受益的唯一地方是Dart VM命令行应用程序/ package:build脚本。在Flutter发行版中将无法使用。

要从中获得结果,可以使用 ports

import 'dart:isolate';

void main() async {
  final name = 'Eval Knievel';
  final uri = Uri.dataFromString(
    '''
    import "dart:isolate";

    void main(_, SendPort port) {
      port.send("Nice to meet you, $name!");
    }
    ''',
    mimeType: 'application/dart',
  );

  final port = ReceivePort();
  await Isolate.spawnUri(uri, [], port.sendPort);

  final String response = await port.first;    
  print(response);
}

I wrote about it on my blog

答案 2 :(得分:0)

至少在Ruby中,Eval()可以从单个语句(如赋值)执行任何操作,以完成所涉及的程序。对于可能的大多数任何其他形式的执行,执行许多小片段存在相当大的时间损失。

仔细观察问题,至少有三种不同的函数位于可能使用eval的各种方案的基础上。 Dart至少以最小的方式处理其中至少2个。

Dart没有,也没有任何计划支持"一般"脚本执行。

然而,NoSuchMethod方法可用于有效地实现动态"注射"变量到您的本地类环境中。它用一个如下所示的字符串替换eval():eval(" String text ='你的名字在这里&#39 ;;");

Dart现在支持的第二个函数是调用方法,如下所示:eval(" Map map = SomeClass.some_method()");

搞砸了之后,我终于明白了一个简单的类可以用来存储调用一个方法所需的信息,对于一个类来说,它似乎具有一般的实用性。我可以替换一个大的易维护的switch语句,否则可能需要调用一系列方法。在Ruby中,这几乎是微不足道的,但是在Dart中有一些不那么直观的调用,所以我想得到这个"技巧"在一个地方,这适合将对您可能需要的字符串进行排序和过滤。

这里的代码是"积累"使用反射将多个类(一个完整的库?)放入一个映射中,这样只需要一个键(作为一个字符串)就可以调用class.methodName()。

注意:我使用了一些"辅助方法"做地图&列表功能,您可能希望用直接Dart替换它们。但是,此代码仅使用函数进行测试..

以下是代码:

//The used "Helpers" here..
MAP_add(var map, var key, var value){ if(key != null){map[key] = value;}return(map);}
Object MAP_fetch(var map, var key, [var dflt = null]) {var value = map[key];if (value==null) {value = dflt;}return( value );}


class ClassMethodMapper {
  Map    _helperMirrorsMap, _methodMap;

  void accum_class_map(Object myClass){
    InstanceMirror helperMirror = reflect(myClass);
    List methodsAr  = helperMirror.type.methods.values;
    String classNm  = myClass.toString().split("'")[1]; ///#FRAGILE      
    MAP_add(_helperMirrorsMap, classNm, helperMirror);
    methodsAr.forEach(( method) {
      String key = method.simpleName;
      if (key.charCodeAt(0) != 95) { //Ignore private methods
        MAP_add(_methodMap, "${classNm}.${key}()", method);
      }
    });
  }

  Map invoker( String methodNm ) {
    var method = MAP_fetch(_methodMap, methodNm, null);
    if (method != null) {         
      String classNm = methodNm.split('.')[0];        
      InstanceMirror helperMirror = MAP_fetch(_helperMirrorsMap, classNm);
      helperMirror.invoke(method.simpleName, []);
    }
  }

  ClassMethodMapper() {
    _methodMap         = {};
    _helperMirrorsMap  = {};
  }
}//END_OF_CLASS( ClassMethodMapper );


============

main() {
   ClassMethodMapper cMM = new ClassMethodMapper();
   cMM.accum_class_map(MyFirstExampleClass);
   cMM.accum_class_map(MySecondExampleClass);

   //Now you're ready to execute any method (not private as per a special line of code above)
   //by simply doing this:
   cMM.invoker( MyFirstExampleClass.my_example_method() );
}