C# 4's Dynamic in Mono

by Miguel de Icaza

C# 4.0 introduces the dynamic type into the language. The language will ship in Visual Studio 2010.

Once a variable is declared as having type dynamic, operations on these value are not done or verified at compile time, but instead happen entirely at runtime.

Marek has been working on Mono's C# 4 implementation and it is coming along nicely. Zoltan wrote a small "PInvoke" dynamic class using Mono's C# compiler that allows you to call C library methods like this:

	dynamic d = new PInvoke ("libc");
	d.printf ("I have been clicked %d times", times);
	

In this case "printf" is resolved at runtime to be a method in the "libc" library. This is similar to Python's ctype library in about 70 lines of C# leveraging LINQ Expression, the Dynamic Language Runtime and C#'s dynamic:

The code is:

using System;
using System.Dynamic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Threading;
using System.Linq.Expressions;

class PInvokeMetaObject : DynamicMetaObject {

    public PInvokeMetaObject (Expression parameter, object o) :
        base (parameter, BindingRestrictions.Empty, o) { }

    public override DynamicMetaObject BindInvokeMember (InvokeMemberBinder binder, DynamicMetaObject[] args) {

        var self = this.Expression;
        var pinvoke = (PInvoke)base.Value;

        var arg_types = new Type [args.Length];
        var arg_exps = new Expression [args.Length];

        for (int i = 0; i < args.Length; ++i) {
            arg_types [i] = args [i].LimitType;
            arg_exps [i] = args [i].Expression;
        }

        var m = pinvoke.GetInvoke (binder.Name, arg_types);
        var target = Expression.Block (
			    Expression.Call (m, arg_exps),
			    Expression.Default (typeof (object)));
        var restrictions = BindingRestrictions.GetTypeRestriction (self, typeof (PInvoke));

        return new DynamicMetaObject (target, restrictions);
    }
}

public class PInvoke : DynamicObject {
    string dll;

    AssemblyBuilder ab;
    ModuleBuilder moduleb;
    int id_gen;

    public PInvoke (string dll) {
        this.dll = dll;
    }

    public override DynamicMetaObject GetMetaObject (Expression parameter) {
        return new PInvokeMetaObject (parameter, this);
    }

    public MethodInfo GetInvoke (string entry_point, Type[] arg_types) {
        if (ab == null) {
            AssemblyName aname = new AssemblyName ("ctype");
            ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run);
            moduleb = ab.DefineDynamicModule ("ctype");
        }

        // Can't use DynamicMethod as they don't support custom attributes
        var tb = moduleb.DefineType ("ctype_" + Interlocked.Increment (ref id_gen) + "_" + entry_point);

        tb.DefinePInvokeMethod ("Invoke", dll, entry_point,
			    MethodAttributes.Static|MethodAttributes.PinvokeImpl,
			    CallingConventions.Standard, typeof
			    (void), arg_types,
			    CallingConvention.StdCall, CharSet.Auto);

        var t = tb.CreateType ();
        var m = t.GetMethod ("Invoke", BindingFlags.Static|BindingFlags.NonPublic);

        return m;
    }
}

public class Tests
{
    public static void Main (String[] args) {
        dynamic d = new PInvoke ("libc");

        for (int i = 0; i < 100; ++i)
            d.printf ("Hello, World %d\n", i);
    }
}    
	

You can download the C# 4.0 Future document for details.

Mono's C# 4 compiler so far implements optional parameters, named parameters, has support for the new covariant and contravariant specifiers and the dynamic keyword is evolving very quickly (as shown by the example above).

If you want to test drive Mono's C# 4.0 compiler, you need Mono from Git and you must pass the "--enable-profile4=yes" argument. Once you do this, the new compiler will be installed as dmcs on your system.

Nikhil has a nice sample that shows JSon integrated directly into C#.

Posted on 11 Aug 2009