有没有办法让这个场景有效?
有一个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)
{
...
}
Closure
和PythonFunction
是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程序集,而不是调用脚本本身。
答案 0 :(得分:8)
排序。您无法直接从C#代码访问Python方法。除非您正在使用C#4.0和动态关键字,否则您非常非常特别;)。但是,您可以将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“存根”,还展示了如何创建访问Python类中方法的C#函数调用。
答案 1 :(得分:6)
clr.CompileModules
纯粹是一个加载时优化 - 它不会使脚本直接可用于像C#这样的静态语言。您需要托管IronPython运行时,然后您可以将DLL加载到运行时并使用IronPython的托管接口来访问它。