Is there any way to make this scenario work?
There is a Python script. It is built into a DLL by running this script with IronPython:
import clr
clr.CompileModules("CompiledScript.dll", "script.py")
The goal is to call this DLL's methods from C# code. .NET Reflector shows there is one class in the DLL - DLRCashedCode
and the methods we are interested in are private static methods of this class.
For example, there is a function in the script:
def scriptMethod(self, text):
...
Its representation in the DLL is:
private static object scriptMethod(Closure closure1, PythonFunction $function, object self, object text)
{
...
}
Closure
and PythonFunction
are IronPython classes (from Microsoft.Scripting.dll and IronPython.dll).
So far so good. Is it possible this method to be called by C# code? The idea of using reflection like
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);
seems harder because of setting the method's parameters. If they are (any how) initialized correctly, could we expect the method to work smoothly?
Is there a better way to call this methods from C#? For various different reasons we prefer to have the script built as a .NET assembly and not to call the script itself.
Sort of. You cannot access the Python methods directly from C# code. Unless you are playing with C# 4.0 and the dynamic keyword or you are very, very special ;). However, you can compile an IronPython class to a DLL and then use IronPython hosting in C# to access the methods (this is for IronPython 2.6 and .NET 2.0).
Create a C# program like this:
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);
}
}
}
Make a trivial Python class like this:
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
Compile it (I use SharpDevelop) but the clr.CompileModules
method should also work. Then shove the compiled MyClass.dll
into the directory where the compiled C# program lives and run it. You should get this as the result:
Hello World!
I'm in a compiled class (I hope)
in some method
in some method
True
False
Press any key to continue . . .
This incorporates Jeff's more direct solution that eliminates having to create and compile a small Python 'stub' and also shows how you can create C# function calls that access the methods in the Python class.
The clr.CompileModules
is purely a load-time optimization - it doesn't make the scripts directly available to a static languge like C#. You'll need to host the IronPython runtime, and then you can load the DLL into the runtime and use IronPython's hosting interfaces to access it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With