c#-具有可变数量的参数的IronPython函数作为委托

在IronPython中,我尝试使用来自C#的不同数量的参数调用PythonFunction.例如;

我想要做:

def foo(a, b):
     print a, b

def bar(a, b, c = None):
     print a, b, c

p = App.DynamicEvent()
p.addHandler(foo)
p.addHandler(bar)
p.invoke("Not", "Working")

其中addHandler接受一个参数,并以某种方式将其存储在要调用的方法列表中,并且invoke具有如下签名:

public virtual void invoke(params object[] tArgs)

因为我想避免使其特定于PythonEngine(以及因此是engine.Operations.Invoke()),所以我尝试了几种将这些东西作为委托进行存储和实现的方法,但我认为问题的症结在于我没有不知道如何存储与PythonFunction兼容的某种MulticastDelegate基本类型?

也许我想实现自己的DynamicInvoke方法?任何想法和经验将不胜感激!

想要这样做的原因是,我想通过C#将密封的Java脚本引擎进行的调用透明地映射到IronPython中.即在Javascript调用中:Client.doThing(“ something”,4,{“ key:” value“})
并在python中使用以下命令处理它:

def doThing(s, i, d):
    pass

使用以下动态事件绑定:

doThingEvent = App.DynamicEvent()
doThingEvent.addHandler(doThing)
WebBrowser.handleMethod("doThing", doThingEvent);

解决方法:

我的第一个想法是digEmAll提出的,但是我想出了一个更好的解决方案,不需要强制转换为System.Action或任何调用时类型检查或分支.只需重载addHandler即可使用PythonFunction和Delegate,这意味着您可以使用原始代码:

def foo(a, b):
     print a, b

def bar(a, b, c = None):
     print a, b, c

p = DynamicEvent(engine)
p.addHandler(foo)
p.addHandler(bar)

p.invoke("a", "b")
p.invoke("a", "b", "c")

使用此C#代码:

public class DynamicEvent
{
    private Dictionary<int, Action<object[]>> delegates = new Dictionary<int, Action<object[]>>();
    public ScriptEngine Engine { get; set; }


    public DynamicEvent(ScriptEngine engine)
    {
        Engine = engine;
    }

    public void addHandler(PythonFunction pythonFunction)
    {
        int args = (int) pythonFunction.func_code.co_nlocals;
        delegates.Add(args, a => Engine.Operations.Invoke(pythonFunction, a));
    }

    public void addHandler(Delegate d)
    {
        int args = d.Method.GetParameters().Length;
        delegates.Add(args, a => d.DynamicInvoke(a));
    }

    public void invoke(params object[] args)
    {
        Action<object[]> action;
        if(!delegates.TryGetValue(args.Length, out action))
            throw new ArgumentException("There is no handler that takes " + args.Length + " arguments!");

        action(args);
    }
}

请注意,您需要将引擎添加到脚本的作用域,以便可以在构造函数中使用它.

希望能有所帮助!

注意:可以从PythonFunction获得委托并执行它,如下所示:

Delegate target = pythonFunction.__code__.Target;
var result = target.DynamicInvoke(new object[] {pythonFunction, args});

但是它比使用Engine.Operations.Invoke()更依赖于平台,并且Delegate签名与“常规” Delegate不同.

上一篇:.NET数组比IronPython中的列表慢?


下一篇:如何将IronPython实例方法传递给类型为`Func`的(C#)函数参数