44

我在 python 中编写了一个类,我想通过 IronPython 将其包装到 .net 程序集中并在 C# 应用程序中实例化。我已经将该类迁移到 IronPython,创建了一个库程序集并引用了它。现在,我如何真正获得该类的实例?

该类(部分)看起来像这样:

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

    def __init__(self, cardName):

我用 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();
        }
    }
}

为了在 C# 中实例化这个类,我需要做什么?

4

4 回答 4

56

IronPython 类不是.NET 类。它们是 Python 元类 IronPython.Runtime.Types.PythonType 的实例。这是因为 Python 类是动态的,并且支持在运行时添加和删除方法,这是 .NET 类无法做到的。

要在 C# 中使用 Python 类,您需要使用 ObjectOperations 类。此类允许您以语言本身的语义对 python 类型和实例进行操作。例如,它在适当的时候使用魔术方法,自动将整数提升为长整数等。您可以通过查看源代码或使用反射器来了解有关 ObjectOperations 的更多信息。

这是一个例子。Calculator.py 包含一个简单的类:

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

您可以在 .NET 4.0 C# 之前的代码中使用它,如下所示:

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)

您将需要引用程序集 IronPython.dll、Microsoft.Scripting 和 Microsoft.Scripting.Core。

C# 4 使用的动态类型使这变得更加容易。

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

如果您使用带有 NuGet 支持的 Visual Studio 2010 或更高版本,只需执行此操作即可下载并引用相应的库。

Install-Package IronPython
于 2009-02-23T22:14:43.380 回答
32

现在 .Net 4.0 已发布并具有动态类型,此示例应该更新。使用与 m-sharp 的原始答案相同的 python 文件:

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

以下是使用 .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);          

同样,您需要添加对 IronPython.dll 和 Microsoft.Scripting 的引用。

如您所见,源文件的初始设置和创建是相同的。

但是,一旦源代码成功执行,使用 python 函数就容易多了,这要归功于新的“动态”关键字。

于 2010-04-27T15:39:13.937 回答
0

我正在更新 Clever Human 为编译的 IronPython 类 (dll) 提供的上述示例,而不是 .py 文件中的 IronPython 源代码。

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

新动态类型的 C# 4.0 代码如下:

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

参考:

  1. 使用 .NET/CSharp IP 2.6 中的已编译 Python 类
  2. IronPython脚本的静态编译
于 2013-06-11T14:12:29.587 回答
-4

我搜索了高低,恐怕似乎没有太多与此有关的信息。我几乎可以肯定,没有人设计出一种以您想要的干净方式执行此操作的方法。

我认为这是一个问题的主要原因是,为了查看PokerCardC# 应用程序中的类型,您必须将 Python 代码编译为 IL。我不相信那里有任何 Python ->IL 编译器。

于 2009-02-23T21:09:38.887 回答