In IronPython I am trying to call a PythonFunction with different numbers of arguments from C#. For instance;
I want to do:
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")
where addHandler takes a single argument and somehow stores it in a list of methods to be invoked and invoke has a signature like this:
public virtual void invoke(params object[] tArgs)
Because I want to avoid making it specific to the PythonEngine (and thus engine.Operations.Invoke()), I've tried several ways of storing and implementing these things as delegates but I think the crux of my problem is that I don't know how to store some kind of MulticastDelegate base type that is compatible with a PythonFunction?
Perhaps I want to implement my own DynamicInvoke method? Any thoughts and experience would be greatly appreciated!
The reason for wanting to do this is that I want to transparently map calls made from a sealed Javascript engine into IronPython via C#. i.e. in the Javascript call: Client.doThing("something", 4, {"key:"value"})
and handle it in the python with:
def doThing(s, i, d):
pass
using the following dynamic event binding:
doThingEvent = App.DynamicEvent()
doThingEvent.addHandler(doThing)
WebBrowser.handleMethod("doThing", doThingEvent);
You can pass a PythonFunction as a delegate for example by casting to an Action<...>
i.e. in Python by doing something like:
import sys
import clr
import System
from System import *
def foo(a, b):
print a, b
def bar(a, b, c = "N.A."):
print a, b, c
p = App.DynamicEvent()
p.AddHandler( Action[object,object](foo) )
p.AddHandler( Action[object,object,object](bar) )
p.DynamicInvoke("Not", "Working")
In this way your p can be a MulticastDelegate.
Obviously this implies:
For the first problem I think you need to write your own "Delegates invoker", something like:
//
// WARNING: very very rough code here !!
//
public class DynamicEvent
{
List<Delegate> delegates;
public DynamicEvent()
{
delegates = new List<Delegate>();
}
public void AddHandler(Delegate dlgt)
{
delegates.Add(dlgt);
}
public void Invoke(params object[] args)
{
foreach (var del in delegates)
{
var parameters = del.Method.GetParameters();
// check parameters number
if (args.Length != parameters.Length)
continue; // go to next param
// check parameters assignability
bool assignable = true;
for (int i = 0; i < args.Length; i++)
{
if (!parameters[i].ParameterType.IsInstanceOfType(args[i]))
{
assignable = false;
break; // stop looping on parameters
}
}
if (!assignable)
continue; // go to next param
// OK it seems compatible, let's invoke
del.DynamicInvoke(args);
}
}
}
N.B.:
the part checking delegate-parameters compatibility is wrong, is just to give you an idea.
The problem is that I don't know how to check, at runtime, whether a list of object args is compatible with a delegate signature... maybe we should check IronPython source code :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With