包含DLR ScriptRuntime
DLR是微软的一个开源项目.为.NET影城程序提供了动态脚本注入支持.DLR构建的功能包含两个方面,一个是共享的动态类型系统,一个是标准的承载模型.但是VS并没有继承相关的DLL,大家可以从Codeplex获得源码.这里不得不提及CLR,它是整个运行环境的基础,DLR也是运行在其上,这样是由显而易见的好处的,CLR的垃圾垃圾回收,JIT编译,安全模式,DLR也能享用这些底层架构功能,如果我们对垃圾回收进行优化,或者是提供某种功能,那么DLR相应的也能享用这种便利.DLR内部为了提高执行效率,会让自己先编译脚本,然后缓存.这有些类似JIT机制.避免重复加载,解析外部脚本.
在实际业务逻辑中,我们希望能够实时动态执行存储在文件中的代码或者完整一个业务逻辑功能,甚至我们可以动态选择脚本语言引擎,在应用程序域中动态生成脚本,并注入脚本,来达到控制业务逻辑的目的.
ScriptRuntime: 创建 DLR 运行环境,这是整个执行过程的起始点,它表示一个全局的执行状态(比如程序集引用等等)。每个应用程序域(AppDomain)中可以启动多个 ScriptRuntime。
ScriptScope: 构建一个执行上下文,其中保存了环境及全局变量。宿主(Host)可以通过创建不同的 ScriptScope 来提供多个数据隔离的执行上下文。
ScriptEngine: DLR 动态语言(比如 IronPython) 执行类,可于解析和执行动态语言代码。
ScriptSource: 操控动态语言代码的类型,我们可以编译(Compile)、读取(Read Code Lines)或运行(Execute)代码。
CompiledCode: 调用 ScriptSource.Compile() 将源代码编译成 CompiledCode,这样多次执行就无需重复编译,从而提高执行性能。
ObjectOperations: 提供了相关方法,允许我们在宿主(Host)中操作 DLR 对象成员(Member)。
现在我们来构建脚本引擎
应用程序执行脚本的方法有很多种:
1.通过ScriptRuntime.ExcuteFile获得ScriptScope
2.通过ScriptRuntime.UseFile获得ScriptScope
3.通过ScriptRuntime.CreateScope获得ScriptScope,再执行Script>execute或ScriptScope.IncludeFile
4.通过ScriptRuntime.GetEngine或ScriptRuntime.GetEngineByFileName获得ScriptEngine.调用ScriptEngine的CreateScriptSourceFromStrng或CreateScriptSourceFromFile或CreateScriptSourceFromStream创建ScriptSource,再执行ScriptSource.Execute
5.有了ScriptSource也不一定要Execute,可以先调用Compile,产生CompiledCode,最后调用CompiledCOde.Execute.
说了这么多,你肯定觉得每个例子,说个JB,说不定又觉得我在忽悠你,我是那样的人吗?
下面看看JB,不对,是案例:
第一步,安装:我是用的是VS2012,我从http://ironpython.codeplex.com/releases/view/12482下载的是IronPython-2.6.msi(不大,7M作用),直接安装就可以了.使用默认的安装路径就可以了,C:Program Files(86)IronPython 2.6(这是我的默认路径)
第二步:引入相应的dll
看到引用了吗?右键单击,选择添加引用,将C:Program Files(86)IronPython 2.6的IronPython.dll,Microsoft.Scripting.Core.dll,Microsoft.Scripting.dll三个dll引入进来.
第三步:应用
C:Program FilesIronPython 2.6TutorialTutorial.htm是IronPython的应用指导,写的很仔细。ipy.exe是IronPython 的运行控制台,如果你想学习IronPython 的语法可以使用这个工具。IronPython 的语法这里就不详细介绍了,如果想进一步学习,可以下载IronPython in Action。
看代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
//下面这二个命名空间必须要引入
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
namespace ConsoleApplication20
{
class Program
{
static void Main(string[] args)
{
/*因为本人没学过Python,所以不会,但是我学过shell和JS,感觉语法差不多,大同小异*/
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var strExpression = "1+2";
var sourceCode = engine.CreateScriptSourceFromString(strExpression);
var actual = sourceCode.Execute<int>();
Console.WriteLine(actual);
Console.ReadKey();
}
}
}
这段代码是用来计算1+2的结果.
ScriptEngine和ScriptScope是在.net中使用IronPython脚本的两个基础类,ScriptSource是运行IronPython的基础类,这里sourceCode就是一个ScriptSource.
有时我们希望给IronPython代码中传入一个变量值:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
//下面这二个命名空间必须要引入
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
namespace ConsoleApplication20
{
class Program
{
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var strExpression = ""hello:" + str ";
var sourceCode = engine.CreateScriptSourceFromString(strExpression);
scope.SetVariable("str","python");
var actual=sourceCode.Execute<string>(scope);
scope.RemoveVariable("str");
Console.WriteLine(actual);
Console.ReadKey();
}
}
}
C#调用IronPython函数
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var strExpression = @"def MyFunction(n):return 2*n ";
var sourceCode = engine.CreateScriptSourceFromString(strExpression).Compile().Execute(scope);
var func = engine.GetVariable<Func<int, int>>(scope, "MyFunction");
Console.WriteLine(func(3));
Console.ReadKey();
这里需要注意def MyFunction(n):前面不能有空格,return 2*n必须有空格
IronPython调用C#函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
//下面这二个命名空间必须要引入
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
namespace ConsoleApplication20
{
class Program
{
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var strExpression = "CMethod('Python')";
var sourceCode = engine.CreateScriptSourceFromString(strExpression);
scope.SetVariable("CMethod", (Func<string, string>)TMethod);
var actual = sourceCode.Execute<string>(scope);
scope.RemoveVariable("CMethod");
Console.WriteLine(actual);
Console.ReadKey();
}
public static string TMethod(string info)
{
return "Hello:" + info;
}
}
}
案例:如果需要使用某个对象中的某个函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
//下面这二个命名空间必须要引入
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
namespace ConsoleApplication20
{
class Program
{
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
Test test = new Test();
var strExpression = @"test.Hello()
";
var sourceCode = engine.CreateScriptSourceFromString(strExpression);
scope.SetVariable("test", test);
var actual = sourceCode.Execute<string>(scope);
Console.WriteLine(actual);
Console.ReadKey();
}
}
public class Test
{
public void Hello()
{
Console.WriteLine("hello ,world");
}
}
}
案例:如果需要在IronPython实例化使用某个对象,就稍微复杂一点:
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IronPythonTest
{
class Program
{
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var strExpression = @"
import clr, sys
clr.AddReference('IronPythonTest')
from IronPythonTest import *
test=Test()
test.Hello()
";
var sourceCode = engine.CreateScriptSourceFromString(strExpression);
var actual = sourceCode.Execute<string>(scope);
Console.WriteLine(actual);
Console.ReadKey();
}
}
public class Test
{
public string Hello()
{
return "Hello World";
}
}
}