Pergunta

Eu escrevi uma classe em python que eu quero embrulhar em um .NET assembly via IronPython e instanciar em um aplicativo C #. Eu já migraram da classe de IronPython, criou uma biblioteca de montagem e referenciado-lo. Agora, como faço para realmente obter uma instância dessa classe?

Os olhares de classe (parcialmente) como este:

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

    def __init__(self, cardName):

O stub de teste que eu escrevi em 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();
        }
    }
}

O que eu tenho que fazer, a fim de criar uma instância dessa classe em C #?

Foi útil?

Solução

classes IronPython são não .NET classes. Eles são instâncias de IronPython.Runtime.Types.PythonType que é o metaclass Python. Isso ocorre porque as classes Python são dinâmicas e adição de suporte e remoção de métodos em tempo de execução, coisas que você não pode fazer com classes de .NET.

Para usar classes Python em C # você precisará usar a classe ObjectOperations. Esta classe permite operar em tipos de python e instâncias na semântica da própria linguagem. por exemplo. ele usa os métodos mágicos quando apropriado, auto-promove inteiros para longs etc. Você pode descobrir mais sobre ObjectOperations por olhar para a fonte ou usando reflector.

Aqui está um exemplo. Calculator.py contém uma classe simples:

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

Você pode usá-lo em seu código # 4.0 C .NET pré assim:

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)

Você vai precisar fazer referência as assembléias IronPython.dll, Microsoft.Scripting e Microsoft.Scripting.Core.

C # 4 fez isso muito mais fácil com o new tipo dinâmico.

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 você estiver usando o Visual Studio 2010 ou posterior com NuGet apoio simplesmente executar este para baixar e referenciar as bibliotecas apropriadas.

Install-Package IronPython

Outras dicas

Agora que .NET 4.0 é liberado e tem o tipo dinâmico, este exemplo deve ser atualizado. Usando o mesmo arquivo de python como na resposta original do m-sharp:

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

Aqui está como você chamaria isso utilizando .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);          

Mais uma vez, você precisa adicionar referências a IronPython.dll e Microsoft.Scripting.

Como você pode ver, a configuração inicial e criar o arquivo de origem é a mesma.

Mas uma vez que a fonte seja com sucesso executado, trabalhando com as funções do Python é muito mais fácil graças à nova palavra-chave "dinâmico".

Estou atualizando o exemplo acima fornecida pelo inteligente Humano para as classes IronPython compilados (DLL) em vez de código fonte IronPython em um arquivo .py.

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

C # 4.0 código com o novo tipo de dinâmica é a seguinte:

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

Referências:

  1. Usando classes Python compilados a partir de .NET / CSharp IP 2.6
  2. estática Compilation de scripts de IronPython

Tenho pesquisado alta e baixa e tenho medo que não parece ser muito mais informações relativas a este. Estou praticamente certo que ninguém planejou uma maneira de fazer isso de forma limpa que você gostaria.

A principal razão pela qual eu acho que este é um problema é que, a fim de ver o tipo PokerCard em seu aplicativo C # você teria que compilar o código Python para IL. Eu não acredito que existam compiladores Python->IL lá fora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top