随着IronPyhon 2.0 的发布,.NET Dynamic Language Runtime 也更加成熟了,在2.0中我们可以用动态脚本以粘合剂的方式编写架构体系中的各种逻辑单元,既便于修改,又能灵活适合多变的业务场景。当然,我的目标是在 Platform Framework 中能嵌入脚本引擎,而不是用 ipy.exe 去执行一个 "独立" 的任务。要让.net 项目能真正跟脚本进行交互,还得需要提供脚本引擎的实现。这得提到DLR一些基本 概念了。
下图摘自 DLR 帮助文件,通过它我们基本可以了解基于 DLR 的组成方式。
下图描述了 DLR 的基本执行流程。
ScriptRuntime: 创建 DLR 运行环境,这是整个执行过程的起始点,它表示一个全局的执行状态(比如程序集引用等等)。每个应用程序域(AppDomain)中可以启动多个 ScriptRuntime。
ScriptScope: 构建一个执行上下文,其中保存了环境及全局变量。宿主(Host)可以通过创建不同的 ScriptScope 来提供多个数据隔离的执行上下文。
ScriptEngine: DLR 动态语言(比如 IronPython) 执行类,可于解析和执行动态语言代码。
ScriptSource: 操控动态语言代码的类型,我们可以编译(Compile)、读取(Read Code Lines)或运行(Execute)代码。
CompiledCode: 调用 ScriptSource.Compile() 将源代码编译成 CompiledCode,这样多次执行就无需重复编译,从而提高执行性能。
ObjectOperations: 提供了相关方法,允许我们在宿主(Host)中操作 DLR 对象成员(Member)。
现在我们来构建脚本引擎
当然我们必须加入IronPyhton提供的相关引用并导入命名空间
using IronPython.Hosting;
using IronPython.Compiler;
using IronPython.Runtime;
using Microsoft.Scripting;
using System.Runtime.Remoting;
Hello World
Code
var py = @"
def test():
return ‘hello world~!’;
print test();";
var engine = Python.CreateEngine();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
code.Execute();
输出: hello world~!
注意:Python 对于源代码缩进的格式有严格要求。
给Python上下文提供变量
var scope = engine.Runtime.Globals; //engine.Runtime.CreateScope();
scope.SetVariable("x", 123);
读取Python上下文中的变量
var x = scope.GetVariable<int>("x");
可以看出 ScriptScope 可以在 Host 和 ScriptRuntime 间传递数据。
对象实例共享
Code
var py = @"
o.X = o.X + 2;
print o.X;";
var engine = Python.CreateEngine();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
var scope = engine.Runtime.Globals;
var o = new Data { X = 123 };
scope.SetVariable("o", o);
code.Execute(scope);
Console.WriteLine(o.X);
载入程序集并由ScriptRuntime管理
创建程序集test.dll
namespace My.Library
{
public class MyClass
{
public int Test(int x)
{
return ++x;
}
}
}
创建Host程序
Code
var py = @"
import clr;
from My.Library import MyClass;
from System import Console;
o = MyClass();
x.X = o.Test(x.X);
Console.WriteLine(x.X);";
var engine = Python.CreateEngine();
engine.Runtime.LoadAssembly(Assembly.GetAssembly(typeof(int))); // mscorlib.dll
engine.Runtime.LoadAssembly(Assembly.LoadFrom("test.dll")); // test.dll
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
var scope = engine.Runtime.Globals;
var x = new Data { X = 123 };
scope.SetVariable("x", x);
code.Execute(scope);
Console.WriteLine(x.X);
读取Python上下文对象实例属性
Code
var py = @"
class Class1:
def __init__(self):
self.i = 100
def inc(self):
self.i=self.i+100
o = Class1()";
var o = scope.GetVariable("o");
var i = engine.Operations.GetMember<int>(o, "i");
读取Python上下文对象实例方法
engine.Execute("o.inc()", scope); //已经在上下文环境中执行此对象方法