C#からIronPython2.6を呼び出す方法
IronPython2.6RC3が出ているというのに、C#からIronPythonを呼び出して使う方法についてはIronPython1.1の情報だったり2.0系列が多いのでちょいとメモを残しておきます。
IronPython自体のマニュアルに載せてくれればいいんですが、チュートリアルとかには載ってないみたいですね。おそらくDLRをホスティングするもう一段抽象化したところを探しに行けば見つかりそうな気がしますが後で*1。
とりあえず確認したのは以下のようなこと。
- C#からIronPythonのコードを動的に実行
- IronPythonで使いたいアセンブリへの参照をC#で追加する
- C#のアセンブリ内で定義したinterfaceを実装する(継承する)
- IronPythonの変数をC#で受け取る・セットする
- IronPythonの関数をC#から呼び出して返り値を取得する
- IronPythonで定義したクラスをC#で実体化する
まずはVisual Studio*2を起動してC#の「コンソールアプリケーション」のプロジェクトを一つ作ります。(もちろん「Windowsフォームアプリケーション」でもOKです)
次に、上記URLからIronPython-2.6-Bin.zipをダウンロードしましょう。中にいくつかのdllが入っているのを確認したら、先ほどのプロジェクトに必要な参照を追加しましょう。
以下のdllの参照を追加します。
- IronPython.dll
- Microsoft.Scripting.dll
- Microsoft.Scripting.Core.dll
こんな感じです。
これで実行しようとすると、dllが足りねーぞと怒られるので、次のdllも実行ファイルができるフォルダに入れておきます。
- IronPython.Modules.dll
- Microsoft.Dynamic.dll
- Microsoft.Scripting.ExtensionAttribute.dll
使われないMicrosoft.Scripting.Debugging.dllというのがありますが、普通に実行する分には無くても支障ありません*3。
でもって後はコードを書くだけです。
IronPython側 (Scripts/Sample.py)
# -*- coding: utf-8 -*- import clr # C#のアセンブリを参照している # 本来必要なclr.addReferenceの処理はC#側で # 先にやってしまってるので普通にimportするだけで良い from IronTest import * print 'Sample.py Called' # C#でセットした変数を表示する print message_from_csharp # C#側で参照される変数 message_from_python = 'Hello IronPython' def test(num): print "test func called: value %d" % num return "test result" # C#側で定義したインターフェースを実装する class TestPlugin(IPluginBase): def install(self): print "install called"
C#側
using System.Reflection; using System; using System.IO; using Microsoft.Scripting.Hosting; using IronPython.Hosting; namespace IronTest { public interface IPluginBase { void install(); } class Program { static void Main(string[] args) { // スクリプトファイルのパスを求める Assembly assembly = typeof(Program).Assembly; string dirPath = Path.GetDirectoryName(assembly.Location); string scriptPath = Path.Combine(dirPath, "Scripts"); string filePath = Path.Combine(scriptPath, "Sample.py"); // Python スクリプトエンジン生成 ScriptEngine engine = Python.CreateEngine(); // このアセンブリをPython側で参照できるようにしておく // もちろん別のアセンブリにしてそれを参照するようにもできる ScriptRuntime runtime = engine.Runtime; runtime.LoadAssembly(Assembly.LoadFile(assembly.Location)); // Python スクリプトを読み込む ScriptSource source = engine.CreateScriptSourceFromFile(filePath); CompiledCode code = source.Compile(); // スコープ生成 // IronPython に変数を渡したり取得したりするときに使う ScriptScope scope = engine.CreateScope(); // Python側のスコープに変数をセットする scope.SetVariable("message_from_csharp", "Hello CSharp"); // Python スクリプト実行(関数定義、クラス定義が完了する) code.Execute(scope); // スクリプトのスコープ内で生成された変数を取得 Console.WriteLine(scope.GetVariable<string>("message_from_python")); // Python側で定義した関数を呼び出す Console.WriteLine(engine.Execute("test(100)", scope)); // Python側で定義したクラスをインスタンス化 IPluginBase plugin = (IPluginBase)engine.Execute("TestPlugin()", scope); plugin.install(); // enterが押されるまで待機 Console.ReadLine(); } } }
実行結果
Sample.py Called Hello CSharp Hello IronPython test func called: value 100 test result install called
関数呼び出しはengine.ExecuteによるPythonコードの実行なので、オブジェクトを引数に渡すのは難しそうですね。基本的な使い方としては2.0系列と変わってないみたいです。
久しぶりに書いたらはてなのスーパープレ記法の書き方を忘れてた(汗)