I have created a small routine that allows you to use the IronPython runtime to create dynamic Types without requiring you to write any Python code.
The normal use case for IronPython in C# requires you to provide the IronPython runtime with some source code files, which will essentially eval and return to you a context which you can interact with dynamically. With some help on the forums I was able to find a way to provide an IronPython AST to the runtime instead of source code. This will be very useful for MetaSharp, since I already have a lot of mechanisms for creating an AST I will only need to simply create a transformer that will change an existing AST into IronPython AST and you can suddenly compile any DSL into arbitrarily complex object hierarchies at runtime.
One of the reasons for this is that I want to create a language workbench tool, where you can experiment with your transformations dynamically without having to recompile in the traditional sense. Also, it just gives you more options at runtime. This should be very handy.
Here is an example of what I’m talking about. My example code is very simple, create a class that implements a simple .net interface then create an instance of that class and call it’s method. Here is the actual python version:
#sample.py from ConsoleApplication4 import IExample class Example(IExample): def Do(self): return "hello python"
Executing and calling this at runtime in C# is quite easy to do out of the box actually.
var runtime = Python.CreateRuntime(); runtime.LoadAssembly(typeof(IExample).Assembly); dynamic python = runtime.UseFile("sample.py"); var example = (IExample)python.Example(); Console.WriteLine(example.Do());
The rub here though is that you need that python source file laying around somewhere. Or you could generate code, put it in a temp file and use that instead but nonetheless, the creation of the dynamic object is done by creating python code only. My problem was to figure out how to bypass most of the parsing semantics and to provide an AST directly to the runtime instead of code files. The AST could be created by a MetaSharp transform step.
So instead you can now do this:
var runtime = Python.CreateRuntime(); runtime.LoadAssembly(typeof(IExample).Assembly); var iexampleImport = typeof(IExample).Import(); var classDefinition = Dlr.Class( "Example", iexampleImport.ToEnumerable(), Dlr.Function( "Do", Dlr.Self().ToEnumerable(), "hello python!".AsConstant().Return())); dynamic python = runtime.Compile( iexampleImport, classDefinition); var example = (IExample)python.Example(); Console.WriteLine(example.Do());
I won’t go into all of the extension methods I created (see link to source at the end) but suffice it to say that the Dlr.Class method is creating a ClassDefinition object. Passing these into the runtime.Compile method is where all of the magic happens.
Figuring out what to do in the Compile extension method was the real hard part. It’s not well documented and some of the side effects are downright bizarre, clearly the API was not intended to be (mis)used in this way.
Fortunately for you, all you have to do is download the file below and you’re off creating dynamic Types using the DLR!