組み込みの IronPython スクリプトで使用される単純な C# 型がいくつかあります。
//simple type
public class Foo
{
public int a;
public int b;
}
var engine = IronPython.Hosting.Python.CreateEngine();
dynamic scope = engine.CreateScope();
scope.foo = new Foo{ a = 1, b = 2 };
engine.Execute( "print( foo.a )", scope );
機能を追加したいFoo
のですが、コードを変更できません。また、それから派生したり、拡張メソッドを使用したりせず、代わりにデリゲートを使用したいと思います。理想的には、次のようなものを書きたいと思います
scope.AddMemberFunction( scope.foo, "Fun",
new Func<Foo,int>( f => return f.a + f.b ) );
次に、Python スクリプトで直接使用します。
print( foo.Fun() )
これはまさに を使用して実行できることだと思いましたが、これにより、 「Foo」オブジェクトには属性「Fun」がないOperations
という例外が発生します
engine.Operations.SetMember( scope.foo, "Fun",
new Func<Foo, int>( f => f.a + f.b ) );
次に、Python の方法を試しました (たとえば、Foo は名前空間 IronPythonApp にあり、そのアセンブリは engine.Runtime に追加されます)。
import IronPythonApp
def Fun( self ):
return self.a + self.b
IronPythonApp.Foo.Fun = Fun
しかし、これは同様の例外を与えます:組み込み/拡張タイプ 'Foo' の属性を設定できません
ironPython が内部的に生成する Python クラス定義を変更する方法はありますか?
アップデート
Jeff Hardy's answer のように、いくつかのオプションを検討しました。どちらもかなりスケーラブルにすることができる2つの方法があります(ここでは簡単な方法を示しています)
ExpandoObject!
var foo = new Foo { a = 1, b = 2 };
dynamic exp = new ExpandoObject();
exp.Fun = new Func<int>( () => foo.a + foo.b );
exp.a = foo.a; //automating these is not a big deal
exp.b = foo.b; //
//now just add exp to the scope and done.
結局 SetMember を使う
scope.origFoo = new Foo { a = 1, b = 2 };
//the only variable thing in this string is 'origFoo'
//so it's no big deal scaling this
engine.Execute( @"
class GenericWrapper( object ) :
def __init__( self, foo ):
self.foo = foo
def __getattr__( self, name ) :
return getattr( self.foo, name )
foo = GenericWrapper( origFoo )", scope );
//ha, now scope contains something that we can mess with after all
engine.Operations.SetMember( scope.foo, "Fun",
new Func<int>( () => scope.foo.a + scope.foo.b ) );
engine.Execute( "print( foo.Fun() )", scope );