2009-02-23 11 views
40

Ho scritto una classe in python che voglio racchiudere in un .net assembly tramite IronPython e creare un'istanza in un'applicazione C#. Ho migrato la classe in IronPython, creato un assembly di libreria e fatto riferimento a esso. Ora, come faccio a ottenere un'istanza di quella classe?Istanziazione di una classe python in C#

L'aspetto di classe (in parte) come questo:

class PokerCard: 
    "A card for playing poker, immutable and unique." 

    def __init__(self, cardName): 

Lo stub di prova che ho scritto in C# è:

using System; 

namespace pokerapp 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var card = new PokerCard(); // I also tried new PokerCard("Ah") 
      Console.WriteLine(card.ToString()); 
      Console.ReadLine(); 
     } 
    } 
} 

Che cosa devo fare per creare un'istanza di questa classe in C# ?

risposta

51

Le classi IronPython sono non. Classi .NET. Sono istanze di IronPython.Runtime.Types.PythonType che è il metacllo Python. Questo perché le classi Python sono dinamiche e supportano l'aggiunta e la rimozione di metodi in fase di runtime, cose che non si possono fare con le classi .NET.

Per utilizzare le classi Python in C# è necessario utilizzare la classe ObjectOperations. Questa classe ti consente di operare su tipi e istanze python nella semantica della lingua stessa. per esempio. usa i metodi magici quando appropriato, promuove automaticamente interi per lunghi ecc. Puoi trovare ulteriori informazioni su ObjectOperations osservando il sorgente o usando reflector.

Ecco un esempio. Calculator.py contiene una semplice classe:

class Calculator(object): 
    def add(self, a, b): 
     return a + b 

si può utilizzare dal pre .NET 4.0 C# codice come questo:

ScriptEngine engine = Python.CreateEngine(); 
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py"); 
ScriptScope scope = engine.CreateScope(); 

ObjectOperations op = engine.Operations; 

source.Execute(scope); // class object created 
object klaz = scope.GetVariable("Calculator"); // get the class object 
object instance = op.Call(klaz); // create the instance 
object method = op.GetMember(instance, "add"); // get a method 
int result = (int)op.Call(method, 4, 5); // call method and get result (9) 

Sarà necessario fare riferimento alle assemblee IronPython.dll, Microsoft. Scripting e Microsoft.Scripting.Core.

C# 4 ha reso tutto più semplice con il nuovo tipo dinamico .

ScriptEngine engine = Python.CreateEngine(); 
ScriptSource source = engine.CreateScriptSourceFromFile("Calculator.py"); 
ScriptScope scope = engine.CreateScope(); 
source.Execute(scope); 

dynamic Calculator = scope.GetVariable("Calculator"); 
dynamic calc = Calculator(); 
int result = calc.add(4, 5); 

Se si utilizza Visual Studio 2010 o successiva con il supporto NuGet semplicemente eseguire questo per scaricare e fare riferimento alle librerie appropriate.

+1

non ho il rappresentante per modificare questo , ma nell'esempio Calculator.py, il primo "def" dovrebbe essere rientrato. Ottimo esempio, però! Molto utile. Ora che .Net 4.0 è fuori, sarebbe bello vedere un esempio aggiornato. –

+5

Aggiunto un esempio .Net 4.0, utilizzando la stessa classe di esempio Calcolatrice. –

+0

Grazie, ho aggiunto il rientro. –

-4

Ho cercato in alto e in basso e ho paura che non ci siano molte informazioni relative a questo. Sono praticamente certo che nessuno ha escogitato un modo per farlo nel modo pulito che vorresti.

Il motivo principale per cui penso che questo sia un problema è che per vedere il tipo PokerCard nell'applicazione C# dovresti compilare il codice Python in IL. Non credo che ci siano dei compilatori Python -> IL.

31

Ora che .Net 4.0 è rilasciato e ha il tipo dinamico, questo esempio deve essere aggiornato. Utilizzando lo stesso file Python come nella risposta originale m-sharp di:

class Calculator(object): 
    def add(self, a, b): 
     return a + b 

Ecco come si potrebbe chiamare utilizzando .Net 4.0:

string scriptPath = "Calculator.py"; 
ScriptEngine engine = Python.CreateEngine(); 
engine.SetSearchPaths(new string[] {"Path to your lib's here. EG:", "C:\\Program Files (x86)\\IronPython 2.7.1\\Lib"}); 
ScriptSource source = engine.CreateScriptSourceFromFile(scriptPath); 
ScriptScope scope = engine.CreateScope(); 
ObjectOperations op = engine.Operations; 
source.Execute(scope); 

dynamic Calculator = scope.GetVariable("Calculator"); 
dynamic calc = Calculator(); 
return calc.add(x,y);   

Anche in questo caso, è necessario aggiungere i riferimenti a IronPython.dll e Microsoft.Scripting.

Come potete vedere, l'impostazione iniziale e la creazione del file sorgente sono le stesse.

Ma una volta eseguita correttamente la fonte, lavorare con le funzioni python è molto più semplice grazie alla nuova parola chiave "dinamica".

+0

Grazie per aver aggiunto l'esempio! –

+0

Questo davvero aiutato! –

0

Sto aggiornando l'esempio precedente fornito da Clever Human per le classi IronPython compilate (dll) invece del codice sorgente IronPython in un file .py. Codice

# Compile IronPython calculator class to a dll 
clr.CompileModules("calculator.dll", "calculator.py") 

C# 4.0 con il nuovo tipo di dinamica è la seguente:

// IRONPYTHONPATH environment variable is not required. Core ironpython dll paths should be part of operating system path. 
ScriptEngine pyEngine = Python.CreateEngine(); 
Assembly myclass = Assembly.LoadFile(Path.GetFullPath("calculator.dll")); 
pyEngine.Runtime.LoadAssembly(myclass); 
ScriptScope pyScope = pyEngine.Runtime.ImportModule("calculator"); 
dynamic Calculator = pyScope.GetVariable("Calculator"); 
dynamic calc = Calculator(); 
int result = calc.add(4, 5); 

Riferimenti:

  1. Using Compiled Python Classes from .NET/CSharp IP 2.6
  2. Static Compilation of IronPython scripts