開發的時候,經常被策劃頻繁變動的方案而苦惱。這時候就想要加入點動態語言來輔助一下。
在考慮用動態語言之前也曾想過使用動態加載dll的方式,實現基礎接口來調用。在卸載的時候遇到了問題,雖可以通過應用程序域來繞過,但這又加入了應用程序域之間的交互。沒有動態語言來的方便。
IronPython的官網:http://ironpython.codeplex.com/
新建一個項目,ConsoleApplication
然後NuGet添加IronPython包
在Main函數中編寫如下代碼:
ScriptEngine engine = Python.CreateEngine(); ScriptScope scope = engine.CreateScope(); string script = "print('Hello world!')"; var sourceCode = engine.CreateScriptSourceFromString(script); var result = sourceCode.Execute<object>(scope); Console.WriteLine(result);
這裡用到了三個主要類型:ScriptEngine, ScriptScope, ScriptSource
顧名思義ScriptEngine是引擎,ScriptScope相當於一個容器可用於傳遞一些自定義的變量,ScriptSource就是腳本源碼。
運行後輸出結果:Hello world!
將上面的代碼修改如下
ScriptEngine engine = Python.CreateEngine(); ScriptScope scope = engine.CreateScope(); string script = "print('Hello %d' %number)"; scope.SetVariable("number", 123); ScriptSource sourceCode = engine.CreateScriptSourceFromString(script); var result = sourceCode.Execute<object>(scope); Console.WriteLine(result);
輸出結果變為:Hello 123
還可以試試更奇妙的,比如C#定義一個類
public class Foo { public string Name { get; set; } public DateTime Birthday { get; set; } }
傳入這個變量試試,修改Main函數的代碼
ScriptEngine engine = Python.CreateEngine(); ScriptScope scope = engine.CreateScope(); string script = @"print('Hello %s' %foo.Name) foo.DoSth()";//注意這裡換行是必須的 Foo foo = new Foo() { Name = "阿薩德", Birthday = new DateTime(1999,2,2) }; scope.SetVariable("foo", foo); ScriptSource sourceCode = engine.CreateScriptSourceFromString(script); var result = sourceCode.Execute<object>(scope); Console.WriteLine(result);
成功輸出:Hello 阿薩德
那麼如果調用Foo裡的方法呢?可以哦,你可以試一試,還能夠命中斷點呢!
將script字符串替換為文件路徑,使用ScriptEngine的CreateScriptSourceFromFile方法可以執行文件格式的IronPython
新建文件,名為test.py, 將上面的script字符粘貼到文件內。修改文件的屬性為“如果較新則復制”。
那麼Main函數的代碼段就是:
ScriptEngine engine = Python.CreateEngine(); ScriptScope scope = engine.CreateScope(); string path = @"test.py"; Foo foo = new Foo() { Name = "阿薩德", Birthday = new DateTime(1999,2,2) }; scope.SetVariable("foo", foo); ScriptSource sourceCode = engine.CreateScriptSourceFromFile(path); var result = sourceCode.Execute<object>(scope); Console.WriteLine(result);
執行成功,輸出結果不變。
但是此時編輯器對py文件的支持是木有的,此時可以安裝一個插件,Python Tools for Visual Studio 簡稱PTVS,可以在GitHub上獲取到:https://github.com/Microsoft/PTVS/releases
安裝之後,就有了語法高亮和智能提示哦~
這個工具增加了很多對Python的支持,你還能在新建項目中看到新增的Python模板,包括了Django等一些流行的Python網站模板,當然IronPython的模板也是不可少的。
還有一個問題,剛才在foo中定義了Birthday這個屬性,但是它的類型是DateTime,如何在IronPython中使用它呢?
修改test.py文件中的代碼
print('Hello %s' %foo.Name) foo.DoSth() from System import DateTime print("My birthday is %s" %foo.Birthday.ToString())
這裡我使用了from System import DateTime這行語句就引入了DateTime的類型
同樣的,你也可以引入System程序集中的String、TimeSpan等類型,方便得一塌糊塗,比如這樣
from System import *
如果需要添加程序集引用呢?
比如我新建了一個類庫,將Foo類放到了這個新的類庫中,那麼我要使用Foo的時候,只要這樣:
import clr,sys clr.AddReference('Foo') from Foo import Foo foo = Foo() foo.Name = "haha" print('Hello %s' %foo.Name) from System import * print("My birthday is %s" %foo.Birthday.ToString())
或許你的程序將告訴你一個找不到Module的錯誤,那就把Foo.dll拷貝到你的執行目錄下。或者你也可以修改Main函數中的代碼,使用engine.SetSearchPaths(new[]{@"../Foo/bin/Debug"});設置查找類庫的路徑。
如果報告無法在Foo中找到Foo類型,那就是你拷貝Foo類的代碼到類庫中去的時候沒有使用Foo類庫的namespace。
現在已經知道了如何在C#中使用IronPython,以及在IronPython的代碼中使用C#的類型和變量傳遞,那麼就可以在你的C#程序中加入炫酷的腳本語言動態特性了。
關於CreateScriptSource的時機,你或許可以使用FileSystemWatcher類來監視文件修改,不過要注意多線程問題哦。
如果你並不需要在C#中加入IronPython,而僅僅只是想要用Python一樣的語法來做一些.net的程序比如winform、wpf之類的,你可以安裝IronPython的安裝包,安裝包在最上面給出的官網地址中有下載。安裝之後將獲得IronPython單獨運行的環境和相關的文檔。
然後你就可以通過PTVS幫你新增的幾個IronPython項目模板來創建你的IronPython程序了。
而且,他們是支持斷點調試的哦!你是不是有了好點子呢,比如在C#項目中使用Link文件來鏈接IronPython項目中的py文件,^_^
我已經迫不及待地想要寫一個可以編輯腳本的小游戲來玩玩了呢。
最後加一個在GitHub上看到的IronPython的小游戲Sample。