A quick look at the C# 4.0 dynamic type

VS 2010 Beta 1 includes some C# 4.0 features and though I have been reading about some of the new stuff on various blogs and forums, I only got to play with it very recently. Put simply, the dynamic keyword allows you to declare and use types that are not type-checked during compilation. They are resolved at runtime using the DLR.

Here’s a simple class that has a dynamic field, a method that has a dynamic argument, and a dynamic property:

class Dynamic
{
    private dynamic data;

    public void SetData(dynamic data)
    {
        this.data = data;
    }

    public dynamic MetaData { get; set; }

    public void Display()
    {
        Console.WriteLine("{0} {1}, {2} {3}",
            data, data.GetType(), MetaData, MetaData.GetType());
    }
}

Using the class is quite straightforward:

private void Foo()
{
    var d = new Dynamic();
    d.MetaData = 100; <-- Int32
    d.SetData(99); <-- Int32
    d.Display();
    d.MetaData = 100f; <-- Single
    d.SetData("hello"); <-- String
    d.Display();
}

Notice how I keep using different types at runtime for calling the same methods and properties. If you look at the IL via Reflector, you’ll see that dynamic types are internally treated as System.Object. Intellisense within VS 2010 will also give you System.Object members since that’s what they are guaranteed to have.

There are three dynamic calls in the Display method. A nested static class is generated inside the Dynamic class, and it will have one static CallSite<> field per dynamic call. In this case, there are three such fields. Whenever the dynamic calls are made, it’s these DLR call sites that come into play. An extremely simplified explanation of what happens is that the DLR internally uses reflection to figure out what type the dynamic object is at runtime. There is also caching done so that type-matching (or mapping) is not repeated unnecessarily. Of course the implementation is quite complex and you could probably spend weeks going through the code in Reflector. Note that if you make dynamic calls in a different method, there will be another static class generated – so it seems to be one inner class per method.

Consider the following simple method:

public void Test()
{
    var type = data.GetType();
}

A class will be generated similar to the following (I’ve made this easy to read – so this is not an accurate representation of the generated code):

[CompilerGenerated]
private static class SiteContainerForTest
{
    public static CallSite<FUNC<CALLSITE, object, object>> callSiteGetType;
}

And the method Test gets compiled into:

public void Test()
{
    if (SiteContainerForTest.callSiteGetType == null)
    {
        SiteContainerForTest.callSiteGetType = CallSite<Func<CallSite, object, object>>.Create(
            new CSharpInvokeMemberBinder(
                CSharpCallFlags.None,
                "GetType", <-- the name of the dynamic member
                typeof(Dynamic),
                null,
                new CSharpArgumentInfo[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) }
            )
        );
    }

    object type = SiteContainerForTest.callSiteGetType.Target(
      SiteContainerForTest.callSiteGetType,
      this.data <-- the dynamic object
    );
}

The call site’s Target will be of type Func<CallSite, object, object>, and the return type is object (because at compile time that’s what the local variable type was defined as, since we don’t know what type it would be at that time). It’s at this point that dynamic binding is done. Fortunately for us, it’s all done behind the scenes and we are protected from having to write all this code ourselves. Assuming data is an Int32 at this time, Int32‘s GetType is called (and since it doesn’t have one, Object‘s GetType is invoked).

You can also use dynamic types locally (a site container class is generated for the containing method) :

dynamic d = 1;
string s = d.ToString();
Console.WriteLine(s);

d = "dynamic data";
Console.WriteLine(d.Length);

d = 33;

try
{
    int len = d.Length; <-- Invalid dynamic call on an Int32 object
}
catch (RuntimeBinderException ex)
{
    Console.WriteLine(ex.Message);
}

When I try to use the non-existent Length property on an Int32 value, the runtime will throw a RuntimeBinderException. And it even gives a very useful error message : ‘int’ does not contain a definition for ‘Length’.

Overall, one of the most celebrated uses of dynamic types is supposed to be for Office interop. You no longer have to do endless casts and mid-level variables for debugging. It’s just as easy as using classic VBScript. At this point, unless you want to interop with Word or Excel, I can’t think of too many scenarios where this will come in handy. Maybe someone who’s more functionally oriented than I am can think of some common scenarios.

Advertisements

One thought on “A quick look at the C# 4.0 dynamic type

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s