Hi,

I just noticed that actually attaching the sample code might be an useful idea. 
:-)

-----Ursprüngliche Nachricht-----
Von: Markus Schaber 

Hi,

We have some existing C# classes using a custom event implementation which 
calls delegates via reflection[1]. Now, when subscribing to the event exposed 
by that class via IronPython, an ArgumentException is thrown:

Unbehandelte Ausnahme: System.ArgumentException: MethodInfo muss ein 
MethodInfo-Laufzeitobjekt sein.
Parametername: this
   bei System.Reflection.Emit.DynamicMethod.RTDynamicMethod.Invoke(Object obj, 
BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo 
culture)
   bei System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   bei EventTest.Invoke(Object[] args) in 
D:\playgroundSharpDevelop\IronPythonDelegateTest\Program.cs:Zeile 98.
   bei ScriptExecutor.Main() in 
D:\playgroundSharpDevelop\IronPythonDelegateTest\Program.cs:Zeile 37.
Script Finished

I attached a stripped down example program demonstrating this behavior.

Currently, we have a workaround of using a C# wrapper method as demonstrated in 
the example code, but this is cumbersome, as we need to create a C# wrapper for 
every exposed delegate type which uses that custom event implementation 
internally, and we need to call that wrapper explicitly from the script.

I also want to avoid to rewrite the custom event implementation, as one of our 
goals is to add the scripting capability in a non-intrusive way.

Now is there any way I can create a working MethodInfo object from pure 
IronPython?

Best regards

Markus Schaber

[1] The main reason for this custom event implementation is that this 
implementation internally keeps the references to the delegate target as weak 
references, so that subscribing to that event alone does not prevent the object 
from being collected.

--
___________________________
We software Automation.

3S-Smart Software Solutions GmbH
Markus Schaber | Developer
Memminger Str. 151 | 87439 Kempten | Germany | Tel. +49-831-54031-0 | Fax 
+49-831-54031-50

Email: m.scha...@3s-software.com | Web: http://www.3s-software.com CoDeSys 
internet forum: http://forum.3s-software.com Download CoDeSys sample projects: 
http://www.3s-software.com/index.shtml?sample_projects

Managing Directors: Dipl.Inf. Dieter Hess, Dipl.Inf. Manfred Werner | Trade 
register: Kempten HRB 6186 | Tax ID No.: DE 167014915 

using System;
using System.Reflection;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

public class ScriptExecutor
{
        private const string SRC = @"
import clr

def handler(sender, event):
        print 'Python handler: ', sender, ' with arg: ', event

eventtest.Foo += handler

def handler2(sender, event):
        print 'Wrapped python handler: ', sender, ' with arg: ', event

wrapped_handler = eventtest.wrap(handler2)

eventtest.Foo += wrapped_handler
";

        private static void Main()
        {
                try
                {
                        ScriptEngine engine = Python.CreateEngine();
                        ScriptSource scriptSource = 
engine.CreateScriptSourceFromString(SRC, "test.py");

                        
engine.Runtime.LoadAssembly(typeof(ScriptExecutor).Assembly);

                        ScriptScope scope = engine.CreateScope();

                        var instance = new EventTest();

                        scope.SetVariable("eventtest", instance);

                        scriptSource.Execute(scope);

                        instance.Foo += StaticHandler;
                        instance.Foo += new ScriptExecutor().InstanceHandler;

                        instance.Invoke(instance, new FooEventArgs());
                }
                finally
                {
                        Console.WriteLine("Script Finished");
                        Console.ReadLine();
                }
        }

        private static void StaticHandler(object sender, FooEventArgs e)
        {
                Console.WriteLine("Handler in C# called.");
        }

        private void InstanceHandler(object sender, FooEventArgs e)
        {
                Console.WriteLine("Instance handler in C# called.");
        }
}

public class FooEventArgs : EventArgs {}

public delegate void FooEventHandler(object sender, FooEventArgs e);

internal class Wrapper
{
        internal readonly object Instance;
        internal readonly MethodInfo Method;
        internal Wrapper Next;

        public Wrapper(object instance, MethodInfo method, Wrapper next)
        {
                Instance = instance;
                Method = method;
                Next = next;
        }
}

public class EventTest
{
        private Wrapper wrappers;
        public event FooEventHandler Foo
        {
                add
                {
                        wrappers = new Wrapper(value.Target, value.Method, 
wrappers);
                }
                // remove left out as this is a simplified example.
                remove { throw new NotImplementedException(); }
        }

        public void Invoke(params object[] args)
        {
                Wrapper wrapper = wrappers;
                while (wrapper != null)
                {
                        Console.WriteLine("Method: {0}", wrapper.Method);
                        Console.WriteLine("Instance: {0}", wrapper.Instance ?? 
"<null>");

                        if (wrapper.Method != null)
                        {
                                wrapper.Method.Invoke(wrapper.Instance, args);
                        }
                        wrapper = wrapper.Next;
                }
        }

        public FooEventHandler wrap(FooEventHandler pyHandler)
        {
                return (o, e) => pyHandler(o, e);
        }
}
_______________________________________________
Ironpython-users mailing list
Ironpython-users@python.org
http://mail.python.org/mailman/listinfo/ironpython-users

Reply via email to