【问题标题】:Build Python scripts and call methods from C#从 C# 构建 Python 脚本和调用方法
【发布时间】:2010-01-26 12:03:25
【问题描述】:

有什么方法可以让这个场景发挥作用吗?

有一个 Python 脚本。通过使用 IronPython 运行此脚本,它被构建到一个 DLL 中:

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

目标是从 C# 代码调用此 DLL 的方法。 .NET Reflector 表示 DLL 中有一个类 - DLRCashedCode,我们感兴趣的方法是该类的私有静态方法。

例如脚本中有一个函数:

def scriptMethod(self, text):
...

它在DLL中的表示是:

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

ClosurePythonFunction 是 IronPython 类(来自 Microsoft.Scripting.dll 和 IronPython.dll)。

到目前为止一切顺利。 C#代码是否可以调用此方法?像这样使用反射的想法

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

由于设置了方法的参数,似乎更难了。如果它们(以任何方式)正确初始化,我们能否期望该方法能够顺利运行?

有没有更好的方法从 C# 调用这些方法?由于各种不同的原因,我们更喜欢将脚本构建为 .NET 程序集,而不是调用脚本本身。

【问题讨论】:

    标签: c# python ironpython


    【解决方案1】:

    有点。您不能直接从 C# 代码访问 Python 方法。除非您正在使用 C# 4.0 和 dynamic 关键字,或者您非常非常特别;)。但是,您可以将 IronPython 类编译为 DLL,然后在 C# 中使用 IronPython 托管来访问这些方法(这适用于 IronPython 2.6 和 .NET 2.0)。

    像这样创建一个 C# 程序:

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

    像这样创建一个简单的 Python 类:

    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
    

    编译它(我使用SharpDevelop)但clr.CompileModules 方法也应该可以工作。然后将编译后的MyClass.dll 推入编译后的 C# 程序所在的目录并运行它。你应该得到这个结果:

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

    这结合了 Jeff 更直接的解决方案,无需创建和编译小型 Python“存根”,还展示了如何创建 C# 函数调用来访问 Python 类中的方法。

    【讨论】:

    • Jeff Hardy 的回答让我想知道是否没有更直接的方法来使用来自 ScriptEngine 的已编译 dll/python 类...
    • 我稍微简化了代码并添加了对 python 方法的调用。另外,我发现了这个(可能有帮助):codingbox.blogspot.com/2009_11_01_archive.html
    • 哈!我迟到了 30 分钟……我刚刚弄清楚如何直接加载。谢谢杰夫!我认为我们应该更新 IronPython Cookbook 网站!
    • 继续 - 我暂时不会讨论它。
    【解决方案2】:

    clr.CompileModules 纯粹是加载时优化 - 它不会使脚本直接可用于像 C# 这样的静态语言。您需要托管 IronPython 运行时,然后您可以将 DLL 加载到运行时并使用 IronPython 的托管接口来访问它。

    【讨论】:

    • 谢谢。您能否提供一个使用 IronPython 的托管接口访问 DLL 的示例?
    • @Alex:查看 djlawler 的回答和我的评论。
    猜你喜欢
    • 2017-11-02
    • 2012-10-25
    • 1970-01-01
    • 2014-06-25
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多