Script.NET是一種動態的腳本語言,它使得程序可擴展,可定制,和維護性好。和Office系列的VB Script相似,可以在應用中嵌入大量的代碼塊,以便在運行時才執行這些代碼。
Script.NET的設計理念是:簡單(simplicity),有效率(efficiency),容易上手(intuitive)。先通過例子,來做一個基本的了解。
using System; using System.Diagnostics; using System.IO; using ScriptNET; using ScriptNET.Runtime; namespace Debug.Net { class Program { static void Main(string[] args) { RuntimeHost.Initialize(); Script s = Script.Compile("Console.WriteLine('Hello World');"); s.Execute(); RuntimeHost.CleanUp(); } } }
為了編譯這個例子,請先添加對程序集ScriptDotNet.dll的引用,它的Target是.NET 3.5。這個例子可以看出,Script.NET是如何調用.NET Framework的類型,並調用它的方法。再來看一個例子
RuntimeHost.Initialize(); object obj=Script.RunCode(" return 1+1;"); Console.WriteLine(obj);
這個例子演示了,如何運行Script.NET的代碼片段。
作為一門語言,一般會包含語法,數據類型,表達式,語句,這是語言層面的基礎內容。來看下面的表格,
Script.NET支持的數據類型
常量,boolean類型的常量是true或false, null表示對象為空,字符串用單引號括起來。
運算符號:+, -, *, / ,%, ! , | , & , != , > , < , is 。其中is用於對象類型。
請看下面的例子表達式,
X = (y+4)*2;
Y = a[5] + 8;
Z = Math.Sqrt(256);
P = new System.Drawing.Point(3,4);
語句 Script.NET程序是語句的集合,有三種常用的語句:順序(sequencing ),循環(loop),分支(branching)
If ... Then ... Else ... if (Expression) statement else Statement
if (x>0) y = y + 1 ; else y = y ?1; if (x>0) message = 'X is positive';
sum=0;
for(i=0; i<10; i++)
sum = sum + a[i];
arr=[1,2,3,4,5]; sum = 0;
foreach(i in arr ) sum = sum + i;
while (i>0) i = i-1;
switch (expr){
case expr1: statement
...
default: statement
}
switch (i){
case 1: MessageBox.Show('Hello!');
case 2: MessageBox.Show('?');
default: MessageBox.Show('No way');
}
Script.NET是腳本語言,而不是面向對象的OOP語言。通常會將一將代碼片段封裝成函數,函數的定義語法如下
function(id1,id2,…,idn) {
statement}
function fac(n){
if (n==1) return 1;
else return n*fac(n-1);
}
MessageBox.Show(fac(5).ToString());
Func_pointer = fac;
Func_pointer(4);
下面的代碼,演示了Script.NET與Host的交互,從Host中獲取值
RuntimeHost.Initialize(); List<int> vals = new List<int>(); vals.AddRange(new int[] { 1, 2, 3, 4 }); Script script = Script.Compile(@" rez = 0; foreach (number in numbers) rez += number;" ); script.Context.SetItem("numbers", vals); object rez = script.Execute(); Console.WriteLine(rez);
運行程序,輸出結果如下
腳本上下文存儲運行時信息,變量,和引入的類型,它可以引入.NET的對象到腳本中,以運用.NET Framework的強大功能。下面的例子演示Script.NET與Host的類型互操作
class Program { static void Main(string[] args) { RuntimeHost.Initialize(); Type type = RuntimeHost.GetType("A"); object script = Script.RunCode(@" a=new A(); a.Name='From Script.NET'; return a.Name; "); Console.WriteLine(script); } } public class A { public string Name { get; set; } }
在Host中定義類型A,並引用它,可以在Script.NET中直接使用。也可在Host中定義類型,然後把它的值傳到Script.NET中,請看例子
RuntimeHost.Initialize(); Type type = RuntimeHost.GetType("A"); A a = new A(); a.Name = "From Host"; Script script = Script.Compile(@" ab.Name='From Script.NET'; return ab.Name; "); script.Context.SetItem("ab", a); script.Execute(); Console.WriteLine(script);
啟動調試,在script.Execute執行前後,對象a的Name屬性值是不同的。
在Script.NET壓縮包的根目錄,找到配置文件RuntimeConfig.xml,把它添加到項目中。它包含,要引用的程序集,類型映射,和運行Script.NET引擎時,可以指定的初試化代碼。
<References>
<Assembly name="System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" sn="true"/>
</References>
<Types>
<Type alias="string" name="System.String" />
<Type alias="int" name="System.Int32" />
……
</Types>
<Initialization>
<![CDATA[
]]>
</Initialization>
比如,可以在Initialization區域定義數值常量,或是初始化代碼,如下所示
<Initialization>
<![CDATA[
Pi=3.14;
Console.WriteLine('Jack is right');
]]>
</Initialization>
再回到Script.NET腳本代碼中,代碼如下
RuntimeHost.Initialize(new FileStream("RuntimeConfig.xml",FileMode.Open)); Script script = Script.Compile(@" Console.WriteLine(Pi); "); script.Execute(); Console.WriteLine(script);
運行程序,可看到控制台輸郵結果如下
注意,Script.NET的標識符是大小寫敏感的,如果在腳本調用中把Pi寫成了PI,會報異常。
Unhandled Exception: ScriptNET.Runtime.ScriptIdNotFoundException: Namespace PI is not found
Script.NET原來的名稱是S#, 文檔和實際的代碼有差異。我是根據對.NET的理解來推斷它的用法,發生錯誤的原因,再加上它本身是個開放源碼的項目,可以直接集成到現有的應用程序中,發生錯誤也可以源代碼的方式調試。以這種方式,可以將應用程序代碼中,將需要動態編譯的代碼,轉化為Script.NET的腳本,借助於Script.NET的強大功能,增加應用程序的靈活性。