2010-01-26 6 views
10

Y a-t-il un moyen de faire fonctionner ce scénario?Créer des scripts Python et des méthodes d'appel à partir de C#

Il existe un script Python. Il est construit dans une DLL en exécutant ce script avec IronPython:

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

L'objectif est d'appeler les méthodes de cette DLL à partir du code C#. .NET Reflector montre qu'il existe une classe dans la DLL - DLRCashedCode et les méthodes qui nous intéressent sont les méthodes statiques privées de cette classe.

Par exemple, il y a une fonction dans le script:

def scriptMethod(self, text): 
... 

sa représentation dans la DLL est:

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

Closure et PythonFunction sont des classes IronPython (de Microsoft.Scripting.dll et IronPython.dll).

Jusqu'ici tout va bien. Est-il possible que cette méthode soit appelée par le code C#? L'idée d'utiliser la réflexion comme

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); 

semble plus difficile à cause de la définition des paramètres de la méthode. S'ils sont (comment) initialisés correctement, pourrions-nous nous attendre à ce que la méthode fonctionne correctement?

Existe-t-il un meilleur moyen d'appeler cette méthode de C#? Pour diverses raisons, nous préférons que le script soit construit en tant qu'assemblage .NET et ne pas appeler le script lui-même.

Répondre

8

Trier par. Vous ne pouvez pas accéder aux méthodes Python directement à partir du code C#. Sauf si vous jouez avec C# 4.0 et le mot-clé dynamique ou vous êtes très, très spécial;). Cependant, vous pouvez compiler une classe IronPython vers une DLL, puis utiliser l'hébergement IronPython en C# pour accéder aux méthodes (ceci est pour IronPython 2.6 et .NET 2.0).

Créer un programme C# comme ceci:

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); 
     } 
    } 
} 

Faire une classe Python trivial comme ceci:

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 

Compile (je l'utilise SharpDevelop) mais la méthode clr.CompileModules devrait également fonctionner. Ensuite, placez le MyClass.dll compilé dans le répertoire où réside le programme C# compilé et exécutez-le. Vous devriez obtenir ceci comme résultat:

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

Cette incorpore une solution plus directe de Jeff qui évite d'avoir à créer et compiler un petit Python « stub » et montre également comment vous pouvez créer des appels de fonction C# qui ont accès aux méthodes dans la Classe Python.

+0

La réponse de Jeff Hardy me demande s'il n'y a pas une façon plus directe d'utiliser la classe dll/python compilée à partir d'un ScriptEngine ... – djlawler

+0

J'ai simplifié un peu le code et j'ai ajouté un appel à une méthode python. En outre, j'ai trouvé ceci (qui pourrait aider): http://codingbox.blogspot.com/2009_11_01_archive.html – djlawler

+0

Vérifiez http://pastie.org/797185 pour une manière plus directe de le faire. –

6

Le clr.CompileModules est purement une optimisation de temps de chargement - il ne rend pas les scripts directement disponibles à une langue statique comme C#. Vous devez héberger l'environnement d'exécution IronPython, puis vous pouvez charger la DLL dans l'environnement d'exécution et utiliser les interfaces d'hébergement IronPython pour y accéder.

+0

Merci. Pourriez-vous nous aider avec un exemple d'utilisation des interfaces d'hébergement IronPython pour accéder à la DLL? – Alex

+0

@Alex: Voir la réponse de djlawler et mon commentaire. –