从C#创建IronPython类的实例

6
我想在C#中创建一个IronPython类的实例,但是我目前所有的尝试似乎都失败了。
这是我当前的代码:
ConstructorInfo[] ci = type.GetConstructors();

foreach (ConstructorInfo t in from t in ci
                              where t.GetParameters().Length == 1
                              select t)
{
    PythonType pytype = DynamicHelpers.GetPythonTypeFromType(type);
    object[] consparams = new object[1];
    consparams[0] = pytype;
    _objects[type] = t.Invoke(consparams);
    pytype.__init__(_objects[type]);
    break;
}

我能够通过调用t.Invoke(consparams)获取对象的创建实例,但是__init__方法似乎没有被调用,因此我从Python脚本中设置的所有属性都没有使用。即使使用了显式的pytype.__init__调用,构造的对象仍然没有被初始化。

使用ScriptEngine.Operations.CreateInstance也不起作用。

我正在使用.NET 4.0和IronPython 2.6 for .NET 4.0。

编辑: 关于我打算如何做这件事的小澄清:

在C#中,我有一个如下的类:

public static class Foo
{
    public static object Instantiate(Type type)
    {
        // do the instantiation here
    }
}

在Python中,以下代码:

class MyClass(object):
    def __init__(self):
        print "this should be called"

Foo.Instantiate(MyClass)
__init__方法似乎从未被调用。

在查看IronPython源代码后,发现__init__方法被定义为public void init(object o) { }。糟糕。 - user193476
3个回答

10
这段代码适用于IronPython 2.6.1版本。
    static void Main(string[] args)
    {
        const string script = @"
class A(object) :
    def __init__(self) :
        self.a = 100

class B(object) : 
    def __init__(self, a, v) : 
        self.a = a
        self.v = v
    def run(self) :
        return self.a.a + self.v
";

        var engine = Python.CreateEngine();
        var scope = engine.CreateScope();
        engine.Execute(script, scope);

        var typeA = scope.GetVariable("A");
        var typeB = scope.GetVariable("B");
        var a = engine.Operations.CreateInstance(typeA); 
        var b = engine.Operations.CreateInstance(typeB, a, 20);
        Console.WriteLine(b.run()); // 120
    }

根据澄清后的问题进行编辑

    class Program
    {
        static void Main(string[] args)
        {
            var engine = Python.CreateEngine();
            var scriptScope = engine.CreateScope();

            var foo = new Foo(engine);

            scriptScope.SetVariable("Foo", foo);
            const string script = @"
class MyClass(object):
    def __init__(self):
        print ""this should be called""

Foo.Create(MyClass)
";
            var v = engine.Execute(script, scriptScope);
        }
    }

public  class Foo
{
    private readonly ScriptEngine engine;

    public Foo(ScriptEngine engine)
    {
        this.engine = engine;
    }

    public  object Create(object t)
    {
        return engine.Operations.CreateInstance(t);
    }
}

问题在于我没有使用 scope.GetVariable -- 我直接将类型以 C# 的 Type 类的形式传递给 C#,主要是因为我需要从各种地方调用函数,并且该变量可能不一定在那个范围内可用。 - user193476
尽管我回答了自己的问题,但我仍然认为你应该成为被接受的答案 :) - user193476

2

我想我解决了自己的问题——使用.NET Type类似乎已经丢弃了Python类型信息。

将其替换为IronPython.Runtime.Types.PythonType效果非常好。


0

答案实际上并没有提到实例化对象的内容——例如中的计算器类没有构造方法,因此它并没有真正回答我的问题。 - user193476
那个SO Q的解决方案对我很有效,添加一个__init__方法确实可以执行它(使用如上所示的.Operations实例)。我没有.NET 4.0来尝试,但如果他们在4.0转换中破坏了东西,我会感到惊讶的。 - Alex Martelli
那个例子并不完全适合我,因为我将类型本身传递给了C#代码,而不是一个有作用域的变量,即通过函数传递,这可能是为什么__init__方法没有被调用的原因。 - user193476

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接