2010-01-26 34 views
10

¿Hay alguna forma de que este escenario funcione?Crear scripts de Python y llamar a métodos desde C#

Hay una secuencia de comandos de Python. Está construido en un archivo DLL mediante la ejecución de este script con IronPython:

import clr 
clr.CompileModules("CompiledScript.dll", "script.py") 

El objetivo es llamar a los métodos de esta DLL de código C#. .NET Reflector muestra que hay una clase en la DLL - DLRCashedCode y los métodos que nos interesan son los métodos estáticos privados de esta clase.

Por ejemplo, hay una función en el guión:

def scriptMethod(self, text): 
... 

Su representación en la DLL es:

private static object scriptMethod(Closure closure1, PythonFunction $function, object self, object text) 
{ 
... 
} 

Closure y PythonFunction son clases IronPython (de Microsoft.Scripting.dll y IronPython.dll).

Hasta ahora todo bien. ¿Es posible que este método sea llamado por el código C#? La idea de utilizar la reflexión como

Type t = typeof(DLRCachedCode); 

string methodName = "scriptMethod"; 
MethodInfo method = t.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static); 

object[] parameters = new object[] { "param1", "param2" }; // the "params problem" 
method.Invoke(null, parameters); 

parece más difícil debido a la configuración de los parámetros del método. Si son (de cualquier manera) inicializados correctamente, ¿podríamos esperar que el método funcione sin problemas?

¿Existe alguna forma mejor de llamar a este método desde C#? Por diversos motivos, preferimos tener el script creado como un ensamblado .NET y no llamar al script en sí.

Respuesta

8

Tipo de. No puede acceder a los métodos de Python directamente desde el código C#. A menos que juegues con C# 4.0 y la palabra clave dinámica o seas muy, muy especial;). Sin embargo, puede compilar una clase IronPython en una DLL y luego usar el alojamiento IronPython en C# para acceder a los métodos (esto es para IronPython 2.6 y .NET 2.0).

Crear un programa en C# como esto:

using System; 
using System.IO; 
using System.Reflection; 
using IronPython.Hosting; 
using Microsoft.Scripting.Hosting; 
// we get access to Action and Func on .Net 2.0 through Microsoft.Scripting.Utils 
using Microsoft.Scripting.Utils; 


namespace TestCallIronPython 
{ 
    class Program 
    { 
     public static void Main(string[] args) 
     { 
      Console.WriteLine("Hello World!"); 
      ScriptEngine pyEngine = Python.CreateEngine(); 

      Assembly myclass = Assembly.LoadFile(Path.GetFullPath("MyClass.dll")); 
      pyEngine.Runtime.LoadAssembly(myclass); 
      ScriptScope pyScope = pyEngine.Runtime.ImportModule("MyClass"); 

      // Get the Python Class 
      object MyClass = pyEngine.Operations.Invoke(pyScope.GetVariable("MyClass")); 

      // Invoke a method of the class 
      pyEngine.Operations.InvokeMember(MyClass, "somemethod", new object[0]); 

      // create a callable function to 'somemethod' 
      Action SomeMethod2 = pyEngine.Operations.GetMember<Action>(MyClass, "somemethod"); 
      SomeMethod2(); 

      // create a callable function to 'isodd' 
      Func<int, bool> IsOdd = pyEngine.Operations.GetMember<Func<int, bool>>(MyClass, "isodd"); 
      Console.WriteLine(IsOdd(1).ToString()); 
      Console.WriteLine(IsOdd(2).ToString()); 

      Console.Write("Press any key to continue . . . "); 
      Console.ReadKey(true); 
     } 
    } 
} 

hacer una clase Python trivial como esto:

class MyClass: 
    def __init__(self): 
     print "I'm in a compiled class (I hope)" 

    def somemethod(self): 
     print "in some method" 

    def isodd(self, n): 
     return 1 == n % 2 

compilarlo (utilizo SharpDevelop) pero el método clr.CompileModules también debería funcionar. Luego inserte el compilado MyClass.dll en el directorio donde vive el programa compilado C# y ejecútelo. Usted debe conseguir esto como el resultado:

Hello World! 
I'm in a compiled class (I hope) 
in some method 
in some method 
True 
False 
Press any key to continue . . . 

Este incorpora la solución más directa de Jeff que elimina el tener que crear y compilar un pequeño Python 'trozo' y también muestra cómo se puede crear C# Función llamadas que acceden a los métodos en el Clase de Python

+0

La respuesta de Jeff Hardy me hace preguntarme si no hay una forma más directa de usar la clase compilada dll/python desde un ScriptEngine ... – djlawler

+0

Simplifiqué un poco el código y agregué una llamada al método python. Además, encontré esto (que podría ser útil): http://codingbox.blogspot.com/2009_11_01_archive.html – djlawler

+0

Visite http://pastie.org/797185 para obtener una forma más directa de hacerlo. –

6

El clr.CompileModules es puramente una optimización del tiempo de carga, no hace que los scripts estén directamente disponibles para un lenguaje estático como C#. Necesitarás alojar el tiempo de ejecución de IronPython, y luego puedes cargar la DLL en el tiempo de ejecución y usar las interfaces de alojamiento de IronPython para acceder a ella.

+0

Gracias. ¿Podría ayudar con un ejemplo de uso de las interfaces de alojamiento de IronPython para acceder a la DLL? – Alex

+0

@Alex: consulta la respuesta de djlawler y mi comentario. –