IronPythonのホスティング

IronPython側から.NETのクラスライブラリを呼び出す例は見ましたので、C#からIronPythonを使ってみます。
以前、IronPythonスクリプトを実行するだけの例は記事にしているので、今回は実行結果を受け取ったり、IronPythonオブジェクトを操作してみます。

まずは、今回のテストに使うIronPythonソースコード

class Calc:
    def add (self, x, y):
        return x + y

    def subtract (self, x, y):
        return x - y

g = globals ()
calc = Calc()
# C#から呼ばれるときは以下の変数が設定されている
if 'cs_arg1' in g and 'cs_arg2' in g:
    retval = calc.add (cs_arg1, cs_arg2)
else:
    print calc.add (10, 20)

calc.pyと名前を付けて保存します。見ての通り、足し算、引き算を行う単純ならクラスです。
ソースのこの部分に注意してください。

# C#から呼ばれるときは以下の変数が設定されている
if 'cs_arg1' in g and 'cs_arg2' in g:

cs_arg1、cs_arg2が存在するかどうか処理を分けています。これらの変数はC#側から設定します。

次に、IronPythonホスティングするC#側のソースコードです。

using System;
using IronPython.Hosting;
using IronPython.Runtime;

public class Program {
    public static void Main () {
        PythonEngine engine = new PythonEngine ();
        // IronPython側に以下の変数を用意する
        engine.SetVariable ("cs_arg1", 1);
        engine.SetVariable ("cs_arg2", 2);
        // スクリプトの実行
        engine.ExecuteFile ("calc.py");
        // Python上の変数を取得
        object o = engine.GetVariable ("retval");

        Console.WriteLine ("1 + 2 = {0}", o);

        // calc変数(Calcクラスのインスタンス)を取得
        OldInstance self = engine.GetVariable ("calc") as OldInstance;
        // Calcクラスを取得
        OldClass calc = self.__class__ as OldClass;
        // subtractメソッドを取得
        Function3 func3 = calc.__dict__["subtract"] as Function3;
        // 呼び出し
        Console.WriteLine ("1 - 2 = {0}", func3.Call (self, 1, 2));
    }
}
/* 結果
1 + 2 = 3
1 - 2 = -1
 */

これもhost.csと名前を付けて保存します。で、コンパイル

$ csc /r:IronPython.dll host.cs

host.exeを実行すると足し算、引き算が行われますね。

足し算側は単純な例で、C#から引数を渡してIronPython側で計算し、結果のみを取得します。一方、引き算側はcalcオブジェクトを取得してコントロールしています。リフレクション経由にイメージは近いですね。IronPythonのオブジェクトは.NETの型と違い、Hashtableの固まりみたいなものなので、このように使うことになります。