【编者按】Ironpython目前分为两个运行库,一个支持.net4.0以下版本,一个支持.net4.0版本。主要的区别就是dynamic的使用。当然能够使用dynamic确实很方便,但是很多情况第三方库还不支持.net4,只能使用2。0、3。5。现在很多C#调用Ironpython的代码都是采用的dynamic方式,在4.0以下版本是运行不了的。还好找到一篇以前介绍Ironpython/DLR的文章,没有使用dynamic,而且介绍还很全面,转载过来。
随着 IronPython 2.0 的发布,.NET Dynamic Language Runtime 总算快成熟了。一直以来,我都期望着用动态脚本以粘合剂的方式编写架构体系中的变化剧烈的逻辑单元,既便于修改,又能灵活适合多变的业务场景。当然,我的目标是在 Platform Framework 中 Embedding Script Engine,而不是用 ipy.exe 去执行一个 "独立" 的 LogicTask。
首先去 CodePlex 下载 IronPython 2.0,然后创建 ConsoleApplication 用于学习测试。还有,别忘了添加引用和 Namespace。
using IronPython.Hosting;
using IronPython.Compiler;
using IronPython.Runtime;
using Microsoft.Scripting;
using System.Runtime.Remoting;
首先看一个简单的例子。
var engine = Python.CreateEngine();
var r = engine.Execute("2 + 3");
Console.WriteLine(r);
很显然,这几行代码打消了我们诸多的顾虑,事情并没有想想中的复杂。
首先,我们需要了解一些基本的 DLR 概念。下图摘自 DLR 帮助文件,通过它我们基本可以了解基于 DLR 的组成方式。
我们应用的重点是 Common Hosting,至于其他的细节不属于本文关注范围。下图描述了 DLR 的基本执行流程。
接下来,我们看一些具体的演示。
1. 执行代码片段
var py = @"
def test():
return 123;
print test();";
var engine = Python.CreateEngine();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
code.Execute();
输出:
123
注意 Python 对于源代码缩进的格式限制。
2. 使用 ScriptScope 传递数据
var py = @"
x = x + 2;
print x;";
var engine = Python.CreateEngine();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
var scope = engine.Runtime.Globals; //engine.Runtime.CreateScope();
scope.SetVariable("x", 123);
code.Execute(scope);
var x = scope.GetVariable("x");
onsole.WriteLine(x);
输出:
125
125
可以看出 ScriptScope 可以在 Host 和 ScriptRuntime 间传递数据。
3. 变量共享
public class Data
public int X { get; set; }
}
// -------------------
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);
输出:
125
125
当然,我们还可以使用 MarshalByRefObject 来实现不同 AppDomain 间的对象传递。
ublic class Data : MarshalByRefObject
{
public int X { get; set; }
}
// --------------------
var py = @"
import clr;
from System import AppDomain;
print AppDomain.CurrentDomain.FriendlyName;
x.X = x.X + 2;
print x.X;";
var engine = Python.CreateEngine(AppDomain.CreateDomain("NewDomain"));
engine.Runtime.LoadAssembly(Assembly.GetAssembly(typeof(int))); // Load Mscorlib.dll Assembly
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);
输出:
NewDomain
125
125
4. 载入程序集
我们先创建一个测试类库 test.dll。
namespace My.Library
{
public class MyClass
{
public int Test(int x)
{
return ++x;
} }
}
程序集引用由 ScriptRuntime 进行管理。
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);
出:
124
124
5. 操控 DLR 对象
var py = @"
class Class1:
def __init__(self):
self.i = 100
o = Class1()";
var engine = Python.CreateEngine();
var scope = engine.CreateScope();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
code.Execute(scope);
var o = scope.GetVariable("o");
var i = engine.Operations.GetMember(o, "i");
Console.WriteLine(i);
输出:
100
6. ScriptRuntime 生命周期
var py = @"
class Class1:
def __init__(self):
self.i = 100
def inc(self):
self.i = self.i + 100;
o = Class1()";
var runtime = Python.CreateRuntime();
var engine = runtime.GetEngine("py");
var scope = engine.CreateScope();
var code = engine.CreateScriptSourceFromString(py, SourceCodeKind.Statements);
// 执行第一段代码
code.Execute(scope);
var o = scope.GetVariableHandle("o");
Console.WriteLine(engine.Operations.GetMember(o, "i"));
// 执行第二段代码
engine.Execute("o.inc()", scope);
Console.WriteLine(engine.Operations.GetMember(o, "i"));
输出:
100
200
原帖:http://www.rainsts.net/article.asp?id=764