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.