C# - IronPython の連係

C#-IronPython間での値の受け渡しが上手くいったのでメモしておこう。
本当はPythonの標準モジュールをIronPythonで読み込んで*1、それをC#で使おう!へいへい!という作戦だったのだけど、時間が無いのでそれはまた次回。
IronPythonの中の作りはコロコロ変わるため、もしかしたら今後以下のものは使えなくなる恐れがあります(以前の資料はあまり参考にならなかった・・・)。遠い未来にGoogleからここにたどり着いて、今まさにこれを読んで参考にしようとしているそこのあなたは充分注意。
C#3.0 と IronPython2.0.1 を使用しました。

mypython.py

class Foo() :
	def bar( self, a, b ) :
		return a + b

f = Foo()
# Csharpという変数はC#側から渡ってくる
python_result = f.bar( Csharp.Value1, Csharp.Value2 )

print "I'm IronPython !!"

C#

IronPython.dll, Microsoft.Scripting.dll, Microsoft.Scripting.Core.dll
の参照を追加しておく必要があります。(IronPythonのフォルダに入ってる)

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

// 〜略〜

class Program
{
    static void Main( string[] args )
    {
        var test = new ScriptingTest();
        test.Test1();
    }
}

public class ScriptingTest
{
    private ScriptEngine pythonEngine = null;
    private ScriptEngine PythonEngine
    {
        get { return this.pythonEngine ?? (this.pythonEngine = Python.CreateEngine()); }
    }

    private ScriptSource source = null;
    private ScriptSource Source
    {
        get
        {
            if ( this.source == null )
                this.source = this.PythonEngine
                                .CreateScriptSourceFromFile( "./mypython.py", Encoding.UTF8 );
            return this.source;
        }
    }
    
    private ScriptScope scope = null;
    private ScriptScope Scope
    {
        get { return this.scope ?? (this.scope = this.PythonEngine.CreateScope()); }
    }


    //
    // この辺からがメイン
    //

    // IronPython側からアクセスできなくなるので、必ずpublic !
    public class Data<T> {
        public T Value1;
        public T Value2;
    }
    public void Test1()
    {
        // 匿名型は使えなかった
        //var values1 = new { Value1 = "hello, ", Value2 = "world" };
        var values1 = new Data<string>{ Value1 = "hello", Value2 = " world" };
        var values2 = new Data<IronPython.Runtime.List> {
                Value1 = new IronPython.Runtime.List{ 1, "two" },
                Value2 = new IronPython.Runtime.List{ 3, 4, 'A' }
        };

        // values1 を Csharp という名前で渡す
        this.Scope.SetVariable( "Csharp", values1 );
        this.Source.Execute<string>( this.Scope );
        // Pythonスクリプト内の変数名を指定する
        var python_result1 = this.Scope.GetVariable<string>( "python_result" );
        Console.WriteLine( python_result1 );

        this.Scope.SetVariable( "Csharp", values2 );
        this.Source.Execute( this.Scope );
        var python_result2 = this.scope.GetVariable<IronPython.Runtime.List>( "python_result" );
        Console.WriteLine( 
            python_result2.ToList().Aggregate((x, y) => x + ", " + y) );
    }
}

I'm IronPython !!
[]hello world[]
I'm IronPython !!
1, two, 3, 4, A
続行するには何かキーを押してください . . .


リストは、C#でお馴染みのジェネリックListではなく、
IronPythonで実装されているリストを引っ張り出してきてそれを利用します。
Pythonは動的型付けなので渡すリストの中身の型は統一されていなくても良い。
C#で取り出す時はobject扱い。

*1:一筋縄ではいかないけど策はある