Pages

Thursday, May 5, 2011

DLR in C# using Scripting Language

You should note, till now C# has very little Dynamic Language feature. As mentioned in PDC, we will soon have the feature Compiler as Service feature in C# it is really hard to wait for such a thing to happen. As for me, after the dynamic capabilities released with C# 4.0, I was really excited to look deep into it to find out what is possible. In my Internals series, I have already mentioned you some of the details of what is implemented inside of C# to achieve the Dynamic capabilities in the language. The introduction of ExpandoObject and DynamicObject classes and also with the Expression Trees gives an edge to dynamism in C# but still there is something missing in the language.  There is still something missing which will eval a script and return the result as every scripting engine does, like javascript.

Even though there is no comparison between javascript and C# as both are completely different, whereas the former is completely type unsafe and interpreted language while later being strongly typed language, still I want more from the language. One might think, we could dynamically compile the objects either using Reflection.Emit or Expression Trees and evaluate the statements using Reflection apis, but believe me, it is not the right way to go as the complexity will increase very fast.

For such a scenarios, where you dare to find some expression evaluator from C#, it is better to use some scripting languages which runs inside .NET environment, yet allows you to use DLR capabilities. One of such language is IronPython.



IronPython as a Language


IronPython is a language originated from Python, but redefined completely inside .NET Runtime and named as IronPython. It is a scripting language that exposes the DLR capabilities completely from .NET CLR, yet helping the developers to easily embed code, testing apis etc. Hence Python developers will find it easy to grab its features and .NET huge Class Library gives it an extra advantage over Python. Lets look at how IronPython actually works.

Before we start the actual code, lets see how to install :

  1. IronPython is an Open Source language which you can easily get from http://ironpython.codeplex.com/.
  2. After you download you will get a special IronPython console where you can evaluate your python code. 
  3. You will also get some sample code inside the installed directory to know more.
So lets type some code inside your IronPython window to evaluate :




  • Allows you to evaluate expression (1+1 = 2)
  • Created a variable x and initialized the value of it to 10. You should remember, the type of x is taken as System.Int32.
  • Added Clr support to the console and added a Reference from GAC 'System.Windows.Forms'
  • Assigned "Hello World" to a string variable y.
  • Defined a method multiply which returns a + b (mistakenly).
  • After I call multiply(5,2) it will automatically return 7.
  • As "Windows.Forms" namespace is already added , you can invoke a MessageBox from the console. 
You should remember, even though the language is scripted, it is really type safe and dynamic. If you pass 5.2 and 6.3 in multiply method, it will treat the calculation in double while the initial call is between integers.  You can also define classes inside the language.

You can create a class as well. Just take a look :

class MyCustomClass(object);
def Print(self, message): print message
def add(self, x, y) : return x + y

Basically you need to pass self each time you define a method to ensure that it is a member of the class.

Note : Like AddReference which actually points to GAC, you can also use AddReferenceToFile to add a dll outside the GAC. 

If you are keen to learn more about IronPython, read the documentation from here.

IronPython through C#

Now lets move our focus towords hosting an IronPython engine inside your C# application. Lets start a Console Application and add a TextFile inside and write few IronPython code inside (use py as extension for the file).


def add(x, y) : return x + y
def show(str) : print str

Remember to Copy the file to output directory.

Now add Microsoft.Scripting.dll and IronPython.dll which you will find inside the installation directory. Once you are done, lets add the following code :

var python = Python.CreateEngine();
dynamic expandable = python.Runtime.UseFile("somepythontext.py");

dynamic result = expandable.add(10, 20);

Console.WriteLine(result);
Console.WriteLine(result.GetType());

result = expandable.add(10.5, 4.3);
Console.WriteLine(result);
Console.WriteLine(result.GetType());

In the above code, we first create an Engine. An engine is the evaluator of expression or statements from your code. Once you get the Engine, you can run any code inside it. You can think of the Engine as Python console.

Next I have attached the file to the Engine to get a Scope. A Scope is a block which can run individially under its own restriction policies. Eventually the file will define the method add. To call the method, lets take the help of dynamic capabilities of the C# 4.0. We call the method and showed the result in the Console.

You should note the Type of the two calls. The first call will display the type as Int32 while the second shows Double.

It is the most simplest hosting Python inside your C# application.

So to run your code, you need a ScriptEngine and a ScriptScope. Lets create a class which will wrap these into it and lets you run your code :

public class ScriptEvaluator
{
    public ScriptScope Scope { get; set; }

    public ScriptEngine Engine { get; set; }

    public ScriptEvaluator()
    {
        this.Engine = Python.CreateEngine();
        this.Scope = this.Engine.CreateScope();
    }
    public string Eval(string code)
    {
        try
        {
            ScriptSource source =
                this.Engine.CreateScriptSourceFromString(code,
                    SourceCodeKind.Expression);

            object result = source.Execute(this.Scope);
            return result.ToString();
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }
}

The code is very easy to understand and self explanatory. We use Eval method to evaluate our code. We are using CreateScriptSourceFromString to ensure we create custom scope for each expression we run. The constructor creates object of both Engine and Scope in which the expression runs.

To call the script lets put some code in Main :

var script = new ScriptEvaluator();
string input = string.Empty;

while (true)
{
    input = string.Empty;
    Console.WriteLine("Enter expression to evaluate : ");
    input = Console.ReadLine();

    if (input.Equals("exit")) break;

    input = script.Eval(input);
    Console.WriteLine("Result : {0}", input);
                
}

The code actually puts an infinite loop to evaluate scripts. Now if I run the application, I can easily evaluate an expression from the console as shown in the figure.



Download Sample - 31KB

Conclusion

So here is a small demonstration on how you can host IronPython inside your C# application to enable DLR capabilities in the language. There are lots of features in the API which would take lots of time to talk about. So for the time being, try IronPython documentation and google to find out more about the API's available. I hope this post comes helpful to you.

Thank you for reading.

No comments:

Post a Comment

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.