在.NET中嵌入IronPython 交互
隨著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;
1、Hello World
以下為引用的內容:
return ‘hello world~!’;
print test();"var engine = Python.CreateEngine();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
code.Execute();
輸出: hello world~!
注意:Python 對于源代碼縮進的格式有嚴格要求。
2、給Python上下文提供變量
scope.SetVariable(“x”, 123);
3、讀取Python上下文中的變量
可以看出 ScriptScope 可以在 Host 和 ScriptRuntime 間傳遞數據。
4、對象實例共享
以下為引用的內容:
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管理
5、創建程序集test.dll
以下為引用的內容:
{
public class MyClass
{
public int Test(int x)
{
return ++x;
}
}
}
創建Host程序
以下為引用的內容:
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上下文對象實例屬性
以下為引用的內容:
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(o,"i");
讀取Python上下文對象實例方法