How to invoke a IronPython function from C# using the DLR Hosting API
Like I wrote in my previous post, the Hosting API lets you do some very interesting and powerful things with the DLR. One of the things I had listed was the ability to invoke a method implemented in python from C#.
This post describes how to set up the VS IDE and the DLR binaries to create an extremely basic DLR host. So if you are new to DLR you may want to quickly go over the step-by-step procedure to get your dev environment set up.
Here's what you would have to do
1. Create the ScriptRuntime object and get the python engine associated with it
ScriptEngine pyEng = ScriptRuntime.Create().GetEngine("python");
2. Implement a function in python and create a ScriptSource object based on the python code
string pyFunc = @"def isodd(n): return 1 == n % 2;";
ScriptSource source = pyEng.CreateScriptSourceFromString(pyFunc,
SourceCodeKind.Statements);
3. Create a ScriptScope object. This object will act as the context for the python code.
ScriptScope scope = pyEng.CreateScope();
4. Execute the ScriptSource object in the context of the ScriptScope object created in step (3).
source.Execute(scope);
5. From C#, Use the 'GetVariable' method in the ScriptScope to get the delegate to the python function implemented in step 2. ( The GetVariable method lets you access any variable defined in python from C# or VB or any other managed language)
Func<int, bool> IsOdd = scope.GetVariable<Func<int, bool>>("isodd");
6. Invoke the delegate.
bool b = IsOdd(1);
The above steps can be used to invoke any non instance method in python from C#. Instance members can be invoked using a similary but slightly different technique. (I will put up a sample that explains this shortly)
You can find more details about the methods and classes used in this sample in the Hosting API Spec.
Here’s the full sample program.
using System;
using System.Scripting;
using Microsoft.Scripting.Hosting;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
//create a runtime and get the python engine
ScriptEngine pyEng = ScriptRuntime.Create().GetEngine("python");
//implement a python function and create a ScriptSource object out of it
string pyFunc = @"def isodd(n): return 1 == n % 2;";
ScriptSource source = pyEng.CreateScriptSourceFromString(pyFunc,
SourceCodeKind.Statements);
//create a scope to act as the context for the code
ScriptScope scope = pyEng.CreateScope();
//execute the source
source.Execute(scope);
//get a delegate to the python function
Func<int, bool> IsOdd = scope.GetVariable<Func<int, bool>>("isodd");
//invoke the delegate
Console.WriteLine(IsOdd(1));
Console.WriteLine(IsOdd(2));
}
}
}
I hope you find this sample useful. I am planning to post a series of articles on DLR Hosting along similar lines( How To's, step-by-step guides etc). It would be very helpful to get your feedback regarding this. So please leave a comment if you have any questions, suggestions or other feedback.
Comments
Anonymous
June 30, 2008
The power of invoking dynamic language from C#/Java can be demonstrated by showing an application which can take plugins/extensions written in Python/Ruby. I have yet to see a solid example of this. The other approac which I have seen is where you expose a server product's API to be configurable by dynamic languages. Websphere takes this approach (uses Jython).Anonymous
June 30, 2008
ASP.NET How to use the IHttpAsyncHandler in ASP.NET [Via: Mads Kristensen ] SQL Server SQL SERVER -...Anonymous
July 08, 2008
Normal 0 false false false EN-US X-NONE X-NONE MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTableAnonymous
October 15, 2008
Really great information, has given me an idea for a blog of my friends.Anonymous
August 26, 2010
Nice, but what if the function has no return type? Func<void> is not valid...