3

組み込みの 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 );
4

1 に答える 1

2

簡単な答え: いいえ、.NET クラスを変更することはできません。デフォルトでは、メンバーを追加するために必要な動的フックがありません。

最善の策は、クラスをラップして必要なメンバーを追加することです。Python はこれを簡単にします:

class FooWrapper(object):
  def __init__(self, foo):
    self.foo = foo

  def __getattr__(self, name):
    return getattr(self.foo, name)

  def mymethod(self):
    ...

特別なメソッドは、__getattr__通常の属性ルックアップの一部ではない属性に対してのみ呼び出されるため、通常どおりにルックアップmymethod()されますが、それ以外は基になるオブジェクトに転送されます。

C# 側で行う必要がある場合はDynamicObject、関数をサブクラス化してオーバーロードすることで同じことを実現できTry*Memberます。

于 2013-06-11T14:57:59.797 に答える